Skip to content

Commit 0fb8d5e

Browse files
author
ocaisa
authored
Merge pull request #3482 from boegel/copy-ec-from-pr
fix combination of --copy-ec and --from-pr
2 parents 34627ca + 3ce315a commit 0fb8d5e

File tree

7 files changed

+344
-98
lines changed

7 files changed

+344
-98
lines changed

easybuild/framework/easyconfig/tools.py

Lines changed: 72 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,9 @@
5353
from easybuild.tools.build_log import EasyBuildError, print_msg, print_warning
5454
from easybuild.tools.config import build_option
5555
from easybuild.tools.environment import restore_env
56-
from easybuild.tools.filetools import find_easyconfigs, is_patch_file, read_file, resolve_path, which, write_file
57-
from easybuild.tools.github import fetch_easyconfigs_from_pr, download_repo
56+
from easybuild.tools.filetools import find_easyconfigs, is_patch_file, locate_files
57+
from easybuild.tools.filetools import read_file, resolve_path, which, write_file
58+
from easybuild.tools.github import fetch_easyconfigs_from_pr, fetch_files_from_pr, download_repo
5859
from easybuild.tools.multidiff import multidiff
5960
from easybuild.tools.py2vs3 import OrderedDict
6061
from easybuild.tools.toolchain.toolchain import is_system_toolchain
@@ -348,44 +349,13 @@ def det_easyconfig_paths(orig_paths):
348349
ec_files = [path for path in pr_files if path.endswith('.eb')]
349350

350351
if ec_files and robot_path:
351-
# look for easyconfigs with relative paths in robot search path,
352-
# unless they were found at the given relative paths
353-
354-
# determine which easyconfigs files need to be found, if any
355-
ecs_to_find = []
356-
for idx, ec_file in enumerate(ec_files):
357-
if ec_file == os.path.basename(ec_file) and not os.path.exists(ec_file):
358-
ecs_to_find.append((idx, ec_file))
359-
_log.debug("List of easyconfig files to find: %s" % ecs_to_find)
360-
361-
# find missing easyconfigs by walking paths in robot search path
362-
for path in robot_path:
363-
_log.debug("Looking for missing easyconfig files (%d left) in %s..." % (len(ecs_to_find), path))
364-
for (subpath, dirnames, filenames) in os.walk(path, topdown=True):
365-
for idx, orig_path in ecs_to_find[:]:
366-
if orig_path in filenames:
367-
full_path = os.path.join(subpath, orig_path)
368-
_log.info("Found %s in %s: %s" % (orig_path, path, full_path))
369-
ec_files[idx] = full_path
370-
# if file was found, stop looking for it (first hit wins)
371-
ecs_to_find.remove((idx, orig_path))
372-
373-
# stop os.walk insanity as soon as we have all we need (os.walk loop)
374-
if not ecs_to_find:
375-
break
376-
377-
# ignore subdirs specified to be ignored by replacing items in dirnames list used by os.walk
378-
dirnames[:] = [d for d in dirnames if d not in build_option('ignore_dirs')]
379-
380-
# ignore archived easyconfigs, unless specified otherwise
381-
if not build_option('consider_archived_easyconfigs'):
382-
dirnames[:] = [d for d in dirnames if d != EASYCONFIGS_ARCHIVE_DIR]
383-
384-
# stop os.walk insanity as soon as we have all we need (outer loop)
385-
if not ecs_to_find:
386-
break
387-
388-
return [os.path.abspath(ec_file) for ec_file in ec_files]
352+
ignore_subdirs = build_option('ignore_dirs')
353+
if not build_option('consider_archived_easyconfigs'):
354+
ignore_subdirs.append(EASYCONFIGS_ARCHIVE_DIR)
355+
356+
ec_files = locate_files(ec_files, robot_path, ignore_subdirs=ignore_subdirs)
357+
358+
return ec_files
389359

390360

391361
def parse_easyconfigs(paths, validate=True):
@@ -728,3 +698,65 @@ def avail_easyblocks():
728698
easyblock_mod_name, easyblocks[easyblock_mod_name]['loc'], path)
729699

730700
return easyblocks
701+
702+
703+
def det_copy_ec_specs(orig_paths, from_pr):
704+
"""Determine list of paths + target directory for --copy-ec."""
705+
706+
target_path, paths = None, []
707+
708+
# if only one argument is specified, use current directory as target directory
709+
if len(orig_paths) == 1:
710+
target_path = os.getcwd()
711+
paths = orig_paths[:]
712+
713+
# if multiple arguments are specified, assume that last argument is target location,
714+
# and remove that from list of paths to copy
715+
elif orig_paths:
716+
target_path = orig_paths[-1]
717+
paths = orig_paths[:-1]
718+
719+
# if --from-pr was used in combination with --copy-ec, some extra care must be taken
720+
if from_pr:
721+
# pull in the paths to all the changed files in the PR,
722+
# which includes easyconfigs but also patch files (& maybe more);
723+
# do this in a dedicated subdirectory of the working tmpdir,
724+
# to avoid potential trouble with already existing files in the working tmpdir
725+
# (note: we use a fixed subdirectory in the working tmpdir here rather than a unique random subdirectory,
726+
# to ensure that the caching for fetch_files_from_pr works across calls for the same PR)
727+
tmpdir = os.path.join(tempfile.gettempdir(), 'fetch_files_from_pr_%s' % from_pr)
728+
pr_paths = fetch_files_from_pr(pr=from_pr, path=tmpdir)
729+
730+
# assume that files need to be copied to current working directory for now
731+
target_path = os.getcwd()
732+
733+
if orig_paths:
734+
last_path = orig_paths[-1]
735+
736+
# check files touched by PR and see if the target directory for --copy-ec
737+
# corresponds to the name of one of these files;
738+
# if so we should copy the specified file(s) to the current working directory,
739+
# since interpreting the last argument as target location is very unlikely to be correct in this case
740+
pr_filenames = [os.path.basename(p) for p in pr_paths]
741+
if last_path in pr_filenames:
742+
paths = orig_paths[:]
743+
else:
744+
target_path = last_path
745+
# exclude last argument that is used as target location
746+
paths = orig_paths[:-1]
747+
748+
# if list of files to copy is empty at this point,
749+
# we simply copy *all* files touched by the PR
750+
if not paths:
751+
paths = pr_paths
752+
753+
# replace path for files touched by PR (no need to worry about others)
754+
for idx, path in enumerate(paths):
755+
filename = os.path.basename(path)
756+
pr_matches = [x for x in pr_paths if os.path.basename(x) == filename]
757+
if len(pr_matches) == 1:
758+
paths[idx] = pr_matches[0]
759+
elif pr_matches:
760+
raise EasyBuildError("Found multiple paths for %s in PR: %s", filename, pr_matches)
761+
762+
return paths, target_path

easybuild/main.py

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,18 @@
5050
from easybuild.framework.easyconfig.easyconfig import clean_up_easyconfigs
5151
from easybuild.framework.easyconfig.easyconfig import fix_deprecated_easyconfigs, verify_easyconfig_filename
5252
from easybuild.framework.easyconfig.style import cmdline_easyconfigs_style_check
53-
from easybuild.framework.easyconfig.tools import categorize_files_by_type, dep_graph
53+
from easybuild.framework.easyconfig.tools import categorize_files_by_type, dep_graph, det_copy_ec_specs
5454
from easybuild.framework.easyconfig.tools import det_easyconfig_paths, dump_env_script, get_paths_for
5555
from easybuild.framework.easyconfig.tools import parse_easyconfigs, review_pr, run_contrib_checks, skip_available
5656
from easybuild.framework.easyconfig.tweak import obtain_ec_for, tweak
5757
from easybuild.tools.config import find_last_log, get_repository, get_repositorypath, build_option
5858
from easybuild.tools.containers.common import containerize
5959
from easybuild.tools.docs import list_software
60-
from easybuild.tools.filetools import adjust_permissions, cleanup, copy_file, copy_files, dump_index, load_index
61-
from easybuild.tools.filetools import read_file, register_lock_cleanup_signal_handlers, write_file
62-
from easybuild.tools.github import check_github, close_pr, new_branch_github, find_easybuild_easyconfig
63-
from easybuild.tools.github import install_github_token, list_prs, new_pr, new_pr_from_branch, merge_pr
60+
from easybuild.tools.filetools import adjust_permissions, cleanup, copy_files, dump_index, load_index
61+
from easybuild.tools.filetools import locate_files, read_file, register_lock_cleanup_signal_handlers, write_file
62+
from easybuild.tools.github import check_github, close_pr, find_easybuild_easyconfig
63+
from easybuild.tools.github import install_github_token, list_prs, merge_pr, new_branch_github, new_pr
64+
from easybuild.tools.github import new_pr_from_branch
6465
from easybuild.tools.github import sync_branch_with_develop, sync_pr_with_develop, update_branch, update_pr
6566
from easybuild.tools.hooks import START, END, load_hooks, run_hook
6667
from easybuild.tools.modules import modules_tool
@@ -303,12 +304,9 @@ def main(args=None, logfile=None, do_build=None, testing=False, modtool=None):
303304
eb_file = find_easybuild_easyconfig()
304305
orig_paths.append(eb_file)
305306

306-
if len(orig_paths) == 1:
307-
# if only one easyconfig file is specified, use current directory as target directory
308-
target_path = os.getcwd()
309-
elif orig_paths:
310-
# last path is target when --copy-ec is used, so remove that from the list
311-
target_path = orig_paths.pop() if options.copy_ec else None
307+
if options.copy_ec:
308+
# figure out list of files to copy + target location (taking into account --from-pr)
309+
orig_paths, target_path = det_copy_ec_specs(orig_paths, options.from_pr)
312310

313311
categorized_paths = categorize_files_by_type(orig_paths)
314312

@@ -321,17 +319,17 @@ def main(args=None, logfile=None, do_build=None, testing=False, modtool=None):
321319
# determine paths to easyconfigs
322320
determined_paths = det_easyconfig_paths(categorized_paths['easyconfigs'])
323321

324-
if (options.copy_ec and not tweaked_ecs_paths) or options.fix_deprecated_easyconfigs or options.show_ec:
322+
# only copy easyconfigs here if we're not using --try-* (that's handled below)
323+
copy_ec = options.copy_ec and not tweaked_ecs_paths
324+
325+
if copy_ec or options.fix_deprecated_easyconfigs or options.show_ec:
325326

326327
if options.copy_ec:
327-
if len(determined_paths) == 1:
328-
copy_file(determined_paths[0], target_path)
329-
print_msg("%s copied to %s" % (os.path.basename(determined_paths[0]), target_path), prefix=False)
330-
elif len(determined_paths) > 1:
331-
copy_files(determined_paths, target_path)
332-
print_msg("%d file(s) copied to %s" % (len(determined_paths), target_path), prefix=False)
333-
else:
334-
raise EasyBuildError("One of more files to copy should be specified!")
328+
# at this point some paths may still just be filenames rather than absolute paths,
329+
# so try to determine full path for those too via robot search path
330+
paths = locate_files(orig_paths, robot_path)
331+
332+
copy_files(paths, target_path, target_single_file=True, allow_empty=False, verbose=True)
335333

336334
elif options.fix_deprecated_easyconfigs:
337335
fix_deprecated_easyconfigs(determined_paths)
@@ -361,7 +359,7 @@ def main(args=None, logfile=None, do_build=None, testing=False, modtool=None):
361359
if options.regtest or options.aggregate_regtest:
362360
_log.info("Running regression test")
363361
# fallback: easybuild-easyconfigs install path
364-
regtest_ok = regtest([path[0] for path in paths] or easyconfigs_pkg_paths, modtool)
362+
regtest_ok = regtest([x for (x, _) in paths] or easyconfigs_pkg_paths, modtool)
365363
if not regtest_ok:
366364
_log.info("Regression test failed (partially)!")
367365
sys.exit(31) # exit -> 3x1t -> 31
@@ -429,8 +427,9 @@ def main(args=None, logfile=None, do_build=None, testing=False, modtool=None):
429427
if tweaked_ecs_in_all_ecs:
430428
# Clean them, then copy them
431429
clean_up_easyconfigs(tweaked_ecs_in_all_ecs)
432-
copy_files(tweaked_ecs_in_all_ecs, target_path)
433-
print_msg("%d file(s) copied to %s" % (len(tweaked_ecs_in_all_ecs), target_path), prefix=False)
430+
copy_files(tweaked_ecs_in_all_ecs, target_path, allow_empty=False, verbose=True)
431+
432+
clean_exit(logfile, eb_tmpdir, testing)
434433

435434
# creating/updating PRs
436435
if pr_options:

easybuild/tools/config.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
DEFAULT_PKG_TOOL = PKG_TOOL_FPM
102102
DEFAULT_PKG_TYPE = PKG_TYPE_RPM
103103
DEFAULT_PNS = 'EasyBuildPNS'
104+
DEFAULT_PR_TARGET_ACCOUNT = 'easybuilders'
104105
DEFAULT_PREFIX = os.path.join(os.path.expanduser('~'), ".local", "easybuild")
105106
DEFAULT_REPOSITORY = 'FileRepository'
106107
DEFAULT_WAIT_ON_LOCK_INTERVAL = 60
@@ -204,7 +205,6 @@ def mk_full_default_path(name, prefix=DEFAULT_PREFIX):
204205
'pr_branch_name',
205206
'pr_commit_msg',
206207
'pr_descr',
207-
'pr_target_account',
208208
'pr_target_repo',
209209
'pr_title',
210210
'rpath_filter',
@@ -307,6 +307,9 @@ def mk_full_default_path(name, prefix=DEFAULT_PREFIX):
307307
DEFAULT_PKG_TYPE: [
308308
'package_type',
309309
],
310+
DEFAULT_PR_TARGET_ACCOUNT: [
311+
'pr_target_account',
312+
],
310313
GENERAL_CLASS: [
311314
'suffix_modules_path',
312315
],

easybuild/tools/options.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,11 @@
6464
from easybuild.tools.config import DEFAULT_JOB_BACKEND, DEFAULT_LOGFILE_FORMAT, DEFAULT_MAX_FAIL_RATIO_PERMS
6565
from easybuild.tools.config import DEFAULT_MINIMAL_BUILD_ENV, DEFAULT_MNS, DEFAULT_MODULE_SYNTAX, DEFAULT_MODULES_TOOL
6666
from easybuild.tools.config import DEFAULT_MODULECLASSES, DEFAULT_PATH_SUBDIRS, DEFAULT_PKG_RELEASE, DEFAULT_PKG_TOOL
67-
from easybuild.tools.config import DEFAULT_PKG_TYPE, DEFAULT_PNS, DEFAULT_PREFIX, DEFAULT_REPOSITORY
68-
from easybuild.tools.config import DEFAULT_WAIT_ON_LOCK_INTERVAL, DEFAULT_WAIT_ON_LOCK_LIMIT, EBROOT_ENV_VAR_ACTIONS
69-
from easybuild.tools.config import ERROR, FORCE_DOWNLOAD_CHOICES, GENERAL_CLASS, IGNORE, JOB_DEPS_TYPE_ABORT_ON_ERROR
70-
from easybuild.tools.config import JOB_DEPS_TYPE_ALWAYS_RUN, LOADED_MODULES_ACTIONS, LOCAL_VAR_NAMING_CHECK_WARN
71-
from easybuild.tools.config import LOCAL_VAR_NAMING_CHECKS, WARN
67+
from easybuild.tools.config import DEFAULT_PKG_TYPE, DEFAULT_PNS, DEFAULT_PREFIX, DEFAULT_PR_TARGET_ACCOUNT
68+
from easybuild.tools.config import DEFAULT_REPOSITORY, DEFAULT_WAIT_ON_LOCK_INTERVAL, DEFAULT_WAIT_ON_LOCK_LIMIT
69+
from easybuild.tools.config import EBROOT_ENV_VAR_ACTIONS, ERROR, FORCE_DOWNLOAD_CHOICES, GENERAL_CLASS, IGNORE
70+
from easybuild.tools.config import JOB_DEPS_TYPE_ABORT_ON_ERROR, JOB_DEPS_TYPE_ALWAYS_RUN, LOADED_MODULES_ACTIONS
71+
from easybuild.tools.config import LOCAL_VAR_NAMING_CHECK_WARN, LOCAL_VAR_NAMING_CHECKS, WARN
7272
from easybuild.tools.config import get_pretend_installpath, init, init_build_options, mk_full_default_path
7373
from easybuild.tools.configobj import ConfigObj, ConfigObjError
7474
from easybuild.tools.docs import FORMAT_TXT, FORMAT_RST
@@ -78,7 +78,7 @@
7878
from easybuild.tools.environment import restore_env, unset_env_vars
7979
from easybuild.tools.filetools import CHECKSUM_TYPE_SHA256, CHECKSUM_TYPES, expand_glob_paths, install_fake_vsc
8080
from easybuild.tools.filetools import move_file, which
81-
from easybuild.tools.github import GITHUB_EB_MAIN, GITHUB_PR_DIRECTION_DESC, GITHUB_PR_ORDER_CREATED
81+
from easybuild.tools.github import GITHUB_PR_DIRECTION_DESC, GITHUB_PR_ORDER_CREATED
8282
from easybuild.tools.github import GITHUB_PR_STATE_OPEN, GITHUB_PR_STATES, GITHUB_PR_ORDERS, GITHUB_PR_DIRECTIONS
8383
from easybuild.tools.github import HAVE_GITHUB_API, HAVE_KEYRING, VALID_CLOSE_PR_REASONS
8484
from easybuild.tools.github import fetch_easyblocks_from_pr, fetch_github_token
@@ -642,7 +642,7 @@ def github_options(self):
642642
str, 'store', None),
643643
'pr-commit-msg': ("Commit message for new/updated pull request created with --new-pr", str, 'store', None),
644644
'pr-descr': ("Description for new pull request created with --new-pr", str, 'store', None),
645-
'pr-target-account': ("Target account for new PRs", str, 'store', GITHUB_EB_MAIN),
645+
'pr-target-account': ("Target account for new PRs", str, 'store', DEFAULT_PR_TARGET_ACCOUNT),
646646
'pr-target-branch': ("Target branch for new PRs", str, 'store', DEFAULT_BRANCH),
647647
'pr-target-repo': ("Target repository for new/updating PRs (default: auto-detect based on provided files)",
648648
str, 'store', None),

0 commit comments

Comments
 (0)