Skip to content

Commit 2768d12

Browse files
authored
Merge pull request #3805 from Flamefire/github_patch_detection
Correctly resolve templates for patches in extensions when uploading to GitHub
2 parents ccc90a8 + e1bed5f commit 2768d12

File tree

3 files changed

+92
-31
lines changed

3 files changed

+92
-31
lines changed

easybuild/tools/github.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import getpass
3535
import glob
3636
import functools
37+
import itertools
3738
import os
3839
import random
3940
import re
@@ -1013,10 +1014,14 @@ def is_patch_for(patch_name, ec):
10131014

10141015
patches = copy.copy(ec['patches'])
10151016

1016-
for ext in ec['exts_list']:
1017-
if isinstance(ext, (list, tuple)) and len(ext) == 3 and isinstance(ext[2], dict):
1018-
ext_options = ext[2]
1019-
patches.extend(ext_options.get('patches', []))
1017+
with ec.disable_templating():
1018+
# take into account both list of extensions (via exts_list) and components (cfr. Bundle easyblock)
1019+
for entry in itertools.chain(ec['exts_list'], ec.get('components', [])):
1020+
if isinstance(entry, (list, tuple)) and len(entry) == 3 and isinstance(entry[2], dict):
1021+
templates = {'name': entry[0], 'version': entry[1]}
1022+
options = entry[2]
1023+
patches.extend(p[0] % templates if isinstance(p, (tuple, list)) else p % templates
1024+
for p in options.get('patches', []))
10201025

10211026
for patch in patches:
10221027
if isinstance(patch, (tuple, list)):

test/framework/github.py

Lines changed: 79 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,14 @@
3333
import random
3434
import re
3535
import sys
36+
import textwrap
3637
from test.framework.utilities import EnhancedTestCase, TestLoaderFiltered, init_config
3738
from time import gmtime
3839
from unittest import TextTestRunner
3940

4041
import easybuild.tools.testing
4142
from easybuild.base.rest import RestClient
43+
from easybuild.framework.easyconfig.easyconfig import EasyConfig
4244
from easybuild.framework.easyconfig.tools import categorize_files_by_type
4345
from easybuild.tools.build_log import EasyBuildError
4446
from easybuild.tools.config import build_option, module_classes, update_build_option
@@ -803,53 +805,103 @@ def test_github_det_patch_specs(self):
803805
"""Test for det_patch_specs function."""
804806

805807
patch_paths = [os.path.join(self.test_prefix, p) for p in ['1.patch', '2.patch', '3.patch']]
806-
file_info = {'ecs': [
807-
{'name': 'A', 'patches': ['1.patch'], 'exts_list': []},
808-
{'name': 'B', 'patches': [], 'exts_list': []},
809-
]
810-
}
808+
file_info = {'ecs': []}
809+
810+
rawtxt = textwrap.dedent("""
811+
easyblock = 'ConfigureMake'
812+
name = 'A'
813+
version = '42'
814+
homepage = 'http://foo.com/'
815+
description = ''
816+
toolchain = {"name":"GCC", "version": "4.6.3"}
817+
818+
patches = ['1.patch']
819+
""")
820+
file_info['ecs'].append(EasyConfig(None, rawtxt=rawtxt))
821+
rawtxt = textwrap.dedent("""
822+
easyblock = 'ConfigureMake'
823+
name = 'B'
824+
version = '42'
825+
homepage = 'http://foo.com/'
826+
description = ''
827+
toolchain = {"name":"GCC", "version": "4.6.3"}
828+
""")
829+
file_info['ecs'].append(EasyConfig(None, rawtxt=rawtxt))
830+
811831
error_pattern = "Failed to determine software name to which patch file .*/2.patch relates"
812832
self.mock_stdout(True)
813833
self.assertErrorRegex(EasyBuildError, error_pattern, gh.det_patch_specs, patch_paths, file_info, [])
814834
self.mock_stdout(False)
815835

816-
file_info['ecs'].append({'name': 'C', 'patches': [('3.patch', 'subdir'), '2.patch'], 'exts_list': []})
836+
rawtxt = textwrap.dedent("""
837+
easyblock = 'ConfigureMake'
838+
name = 'C'
839+
version = '42'
840+
homepage = 'http://foo.com/'
841+
description = ''
842+
toolchain = {"name":"GCC", "version": "4.6.3"}
843+
844+
patches = [('3.patch', 'subdir'), '2.patch']
845+
""")
846+
file_info['ecs'].append(EasyConfig(None, rawtxt=rawtxt))
817847
self.mock_stdout(True)
818848
res = gh.det_patch_specs(patch_paths, file_info, [])
819849
self.mock_stdout(False)
820850

821-
self.assertEqual(len(res), 3)
822-
self.assertEqual(os.path.basename(res[0][0]), '1.patch')
823-
self.assertEqual(res[0][1], 'A')
824-
self.assertEqual(os.path.basename(res[1][0]), '2.patch')
825-
self.assertEqual(res[1][1], 'C')
826-
self.assertEqual(os.path.basename(res[2][0]), '3.patch')
827-
self.assertEqual(res[2][1], 'C')
851+
self.assertEqual([i[0] for i in res], patch_paths)
852+
self.assertEqual([i[1] for i in res], ['A', 'C', 'C'])
828853

829854
# check if patches for extensions are found
830-
file_info['ecs'][-1] = {
831-
'name': 'patched_ext',
832-
'patches': [],
833-
'exts_list': [
855+
rawtxt = textwrap.dedent("""
856+
easyblock = 'ConfigureMake'
857+
name = 'patched_ext'
858+
version = '42'
859+
homepage = 'http://foo.com/'
860+
description = ''
861+
toolchain = {"name":"GCC", "version": "4.6.3"}
862+
863+
exts_list = [
834864
'foo',
835865
('bar', '1.2.3'),
836866
('patched', '4.5.6', {
837-
'patches': [('2.patch', 1), '3.patch'],
867+
'patches': [('%(name)s-2.patch', 1), '%(name)s-3.patch'],
838868
}),
839-
],
840-
}
869+
]
870+
""")
871+
patch_paths[1:3] = [os.path.join(self.test_prefix, p) for p in ['patched-2.patch', 'patched-3.patch']]
872+
file_info['ecs'][-1] = EasyConfig(None, rawtxt=rawtxt)
873+
874+
self.mock_stdout(True)
875+
res = gh.det_patch_specs(patch_paths, file_info, [])
876+
self.mock_stdout(False)
877+
878+
self.assertEqual([i[0] for i in res], patch_paths)
879+
self.assertEqual([i[1] for i in res], ['A', 'patched_ext', 'patched_ext'])
880+
881+
# check if patches for components are found
882+
rawtxt = textwrap.dedent("""
883+
easyblock = 'PythonBundle'
884+
name = 'patched_bundle'
885+
version = '42'
886+
homepage = 'http://foo.com/'
887+
description = ''
888+
toolchain = {"name":"GCC", "version": "4.6.3"}
889+
890+
components = [
891+
('bar', '1.2.3'),
892+
('patched', '4.5.6', {
893+
'patches': [('%(name)s-2.patch', 1), '%(name)s-3.patch'],
894+
}),
895+
]
896+
""")
897+
file_info['ecs'][-1] = EasyConfig(None, rawtxt=rawtxt)
841898

842899
self.mock_stdout(True)
843900
res = gh.det_patch_specs(patch_paths, file_info, [])
844901
self.mock_stdout(False)
845902

846-
self.assertEqual(len(res), 3)
847-
self.assertEqual(os.path.basename(res[0][0]), '1.patch')
848-
self.assertEqual(res[0][1], 'A')
849-
self.assertEqual(os.path.basename(res[1][0]), '2.patch')
850-
self.assertEqual(res[1][1], 'patched_ext')
851-
self.assertEqual(os.path.basename(res[2][0]), '3.patch')
852-
self.assertEqual(res[2][1], 'patched_ext')
903+
self.assertEqual([i[0] for i in res], patch_paths)
904+
self.assertEqual([i[1] for i in res], ['A', 'patched_bundle', 'patched_bundle'])
853905

854906
def test_github_restclient(self):
855907
"""Test use of RestClient."""

test/framework/sandbox/easybuild/easyblocks/generic/pythonbundle.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
@author: Miguel Dias Costa (National University of Singapore)
2929
"""
3030
from easybuild.framework.easyblock import EasyBlock
31+
from easybuild.framework.easyconfig import CUSTOM
3132

3233

3334
class PythonBundle(EasyBlock):
@@ -37,4 +38,7 @@ class PythonBundle(EasyBlock):
3738
def extra_options(extra_vars=None):
3839
if extra_vars is None:
3940
extra_vars = {}
41+
extra_vars.update({
42+
'components': [(), "List of components to install: tuples w/ name, version and easyblock to use", CUSTOM],
43+
})
4044
return EasyBlock.extra_options(extra_vars)

0 commit comments

Comments
 (0)