Skip to content

Commit 987599c

Browse files
committed
Sort output of eb --search in natural order (respecting numbers)
1 parent ee06900 commit 987599c

File tree

5 files changed

+42
-28
lines changed

5 files changed

+42
-28
lines changed

easybuild/tools/filetools.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
from easybuild.tools.build_log import EasyBuildError, dry_run_msg, print_msg, print_warning
6161
from easybuild.tools.config import DEFAULT_WAIT_ON_LOCK_INTERVAL, GENERIC_EASYBLOCK_PKG, build_option, install_path
6262
from easybuild.tools.py2vs3 import HTMLParser, std_urllib, string_type
63-
from easybuild.tools.utilities import nub, remove_unwanted_chars
63+
from easybuild.tools.utilities import nub, remove_unwanted_chars, natural_keys
6464

6565
try:
6666
import requests
@@ -1021,7 +1021,7 @@ def search_file(paths, query, short=False, ignore_dirs=None, silent=False, filen
10211021
else:
10221022
path_hits.append(os.path.join(path, filepath))
10231023

1024-
path_hits = sorted(path_hits)
1024+
path_hits = sorted(path_hits, key=natural_keys)
10251025

10261026
if path_hits:
10271027
common_prefix = det_common_path_prefix(path_hits)

easybuild/tools/utilities.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,3 +316,10 @@ def time2str(delta):
316316
res = '%d %s %d min %d sec' % (hours, hours_str, mins, secs)
317317

318318
return res
319+
320+
321+
def natural_keys(key):
322+
"""Can be used as the sort key in list.sort(key=natural_keys) to sort in natural order (i.e. respecting numbers)"""
323+
def try_to_int(key_part):
324+
return int(key_part) if key_part.isdigit() else key_part
325+
return [try_to_int(key_part) for key_part in re.split(r'(\d+)', key)]

test/framework/filetools.py

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2158,11 +2158,11 @@ def test_search_file(self):
21582158
self.assertEqual(var_defs, [])
21592159
self.assertEqual(len(hits), 5)
21602160
self.assertTrue(all(os.path.exists(p) for p in hits))
2161-
self.assertTrue(hits[0].endswith('/hwloc-1.11.8-GCC-4.6.4.eb'))
2162-
self.assertTrue(hits[1].endswith('/hwloc-1.11.8-GCC-6.4.0-2.28.eb'))
2163-
self.assertTrue(hits[2].endswith('/hwloc-1.11.8-GCC-7.3.0-2.30.eb'))
2164-
self.assertTrue(hits[3].endswith('/hwloc-1.6.2-GCC-4.9.3-2.26.eb'))
2165-
self.assertTrue(hits[4].endswith('/hwloc-1.8-gcccuda-2018a.eb'))
2161+
self.assertTrue(hits[0].endswith('/hwloc-1.6.2-GCC-4.9.3-2.26.eb'))
2162+
self.assertTrue(hits[1].endswith('/hwloc-1.8-gcccuda-2018a.eb'))
2163+
self.assertTrue(hits[2].endswith('/hwloc-1.11.8-GCC-4.6.4.eb'))
2164+
self.assertTrue(hits[3].endswith('/hwloc-1.11.8-GCC-6.4.0-2.28.eb'))
2165+
self.assertTrue(hits[4].endswith('/hwloc-1.11.8-GCC-7.3.0-2.30.eb'))
21662166

21672167
# also test case-sensitive searching
21682168
var_defs, hits_bis = ft.search_file([test_ecs], 'HWLOC', silent=True, case_sensitive=True)
@@ -2176,9 +2176,12 @@ def test_search_file(self):
21762176
# check filename-only mode
21772177
var_defs, hits = ft.search_file([test_ecs], 'HWLOC', silent=True, filename_only=True)
21782178
self.assertEqual(var_defs, [])
2179-
self.assertEqual(hits, ['hwloc-1.11.8-GCC-4.6.4.eb', 'hwloc-1.11.8-GCC-6.4.0-2.28.eb',
2180-
'hwloc-1.11.8-GCC-7.3.0-2.30.eb', 'hwloc-1.6.2-GCC-4.9.3-2.26.eb',
2181-
'hwloc-1.8-gcccuda-2018a.eb'])
2179+
self.assertEqual(hits, ['hwloc-1.6.2-GCC-4.9.3-2.26.eb',
2180+
'hwloc-1.8-gcccuda-2018a.eb',
2181+
'hwloc-1.11.8-GCC-4.6.4.eb',
2182+
'hwloc-1.11.8-GCC-6.4.0-2.28.eb',
2183+
'hwloc-1.11.8-GCC-7.3.0-2.30.eb',
2184+
])
21822185

21832186
# check specifying of ignored dirs
21842187
var_defs, hits = ft.search_file([test_ecs], 'HWLOC', silent=True, ignore_dirs=['hwloc'])
@@ -2187,28 +2190,34 @@ def test_search_file(self):
21872190
# check short mode
21882191
var_defs, hits = ft.search_file([test_ecs], 'HWLOC', silent=True, short=True)
21892192
self.assertEqual(var_defs, [('CFGS1', os.path.join(test_ecs, 'h', 'hwloc'))])
2190-
self.assertEqual(hits, ['$CFGS1/hwloc-1.11.8-GCC-4.6.4.eb', '$CFGS1/hwloc-1.11.8-GCC-6.4.0-2.28.eb',
2191-
'$CFGS1/hwloc-1.11.8-GCC-7.3.0-2.30.eb', '$CFGS1/hwloc-1.6.2-GCC-4.9.3-2.26.eb',
2192-
'$CFGS1/hwloc-1.8-gcccuda-2018a.eb'])
2193+
self.assertEqual(hits, ['$CFGS1/hwloc-1.6.2-GCC-4.9.3-2.26.eb',
2194+
'$CFGS1/hwloc-1.8-gcccuda-2018a.eb',
2195+
'$CFGS1/hwloc-1.11.8-GCC-4.6.4.eb',
2196+
'$CFGS1/hwloc-1.11.8-GCC-6.4.0-2.28.eb',
2197+
'$CFGS1/hwloc-1.11.8-GCC-7.3.0-2.30.eb'
2198+
])
21932199

21942200
# check terse mode (implies 'silent', overrides 'short')
21952201
var_defs, hits = ft.search_file([test_ecs], 'HWLOC', terse=True, short=True)
21962202
self.assertEqual(var_defs, [])
21972203
expected = [
2204+
os.path.join(test_ecs, 'h', 'hwloc', 'hwloc-1.6.2-GCC-4.9.3-2.26.eb'),
2205+
os.path.join(test_ecs, 'h', 'hwloc', 'hwloc-1.8-gcccuda-2018a.eb'),
21982206
os.path.join(test_ecs, 'h', 'hwloc', 'hwloc-1.11.8-GCC-4.6.4.eb'),
21992207
os.path.join(test_ecs, 'h', 'hwloc', 'hwloc-1.11.8-GCC-6.4.0-2.28.eb'),
22002208
os.path.join(test_ecs, 'h', 'hwloc', 'hwloc-1.11.8-GCC-7.3.0-2.30.eb'),
2201-
os.path.join(test_ecs, 'h', 'hwloc', 'hwloc-1.6.2-GCC-4.9.3-2.26.eb'),
2202-
os.path.join(test_ecs, 'h', 'hwloc', 'hwloc-1.8-gcccuda-2018a.eb'),
22032209
]
22042210
self.assertEqual(hits, expected)
22052211

22062212
# check combo of terse and filename-only
22072213
var_defs, hits = ft.search_file([test_ecs], 'HWLOC', terse=True, filename_only=True)
22082214
self.assertEqual(var_defs, [])
2209-
self.assertEqual(hits, ['hwloc-1.11.8-GCC-4.6.4.eb', 'hwloc-1.11.8-GCC-6.4.0-2.28.eb',
2210-
'hwloc-1.11.8-GCC-7.3.0-2.30.eb', 'hwloc-1.6.2-GCC-4.9.3-2.26.eb',
2211-
'hwloc-1.8-gcccuda-2018a.eb'])
2215+
self.assertEqual(hits, ['hwloc-1.6.2-GCC-4.9.3-2.26.eb',
2216+
'hwloc-1.8-gcccuda-2018a.eb',
2217+
'hwloc-1.11.8-GCC-4.6.4.eb',
2218+
'hwloc-1.11.8-GCC-6.4.0-2.28.eb',
2219+
'hwloc-1.11.8-GCC-7.3.0-2.30.eb',
2220+
])
22122221

22132222
# patterns that include special characters + (or ++) shouldn't cause trouble
22142223
# cfr. https://github.com/easybuilders/easybuild-framework/issues/2966

test/framework/options.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -988,7 +988,7 @@ def test_ignore_index(self):
988988
toy_ec = os.path.join(test_ecs_dir, 'test_ecs', 't', 'toy', 'toy-0.0.eb')
989989
copy_file(toy_ec, self.test_prefix)
990990

991-
toy_ec_list = ['toy-0.0.eb', 'toy-1.2.3.eb', 'toy-4.5.6.eb']
991+
toy_ec_list = ['toy-0.0.eb', 'toy-1.2.3.eb', 'toy-4.5.6.eb', 'toy-11.5.6.eb']
992992

993993
# install index that list more files than are actually available,
994994
# so we can check whether it's used
@@ -998,27 +998,25 @@ def test_ignore_index(self):
998998
args = [
999999
'--search=toy',
10001000
'--robot-paths=%s' % self.test_prefix,
1001+
'--terse',
10011002
]
10021003
self.mock_stdout(True)
10031004
self.eb_main(args, testing=False, raise_error=True)
10041005
stdout = self.get_stdout()
10051006
self.mock_stdout(False)
10061007

1007-
for toy_ec_fn in toy_ec_list:
1008-
regex = re.compile(re.escape(os.path.join(self.test_prefix, toy_ec_fn)), re.M)
1009-
self.assertTrue(regex.search(stdout), "Pattern '%s' should be found in: %s" % (regex.pattern, stdout))
1008+
# Also checks for ordering: 11.x comes last!
1009+
expected_output = '\n'.join(os.path.join(self.test_prefix, ec) for ec in toy_ec_list) + '\n'
1010+
self.assertEqual(stdout, expected_output)
10101011

10111012
args.append('--ignore-index')
10121013
self.mock_stdout(True)
10131014
self.eb_main(args, testing=False, raise_error=True)
10141015
stdout = self.get_stdout()
10151016
self.mock_stdout(False)
10161017

1017-
regex = re.compile(re.escape(os.path.join(self.test_prefix, 'toy-0.0.eb')), re.M)
1018-
self.assertTrue(regex.search(stdout), "Pattern '%s' should be found in: %s" % (regex.pattern, stdout))
1019-
for toy_ec_fn in ['toy-1.2.3.eb', 'toy-4.5.6.eb']:
1020-
regex = re.compile(re.escape(os.path.join(self.test_prefix, toy_ec_fn)), re.M)
1021-
self.assertFalse(regex.search(stdout), "Pattern '%s' should not be found in: %s" % (regex.pattern, stdout))
1018+
# This should be the only EC found
1019+
self.assertEqual(stdout, os.path.join(self.test_prefix, 'toy-0.0.eb') + '\n')
10221020

10231021
def test_search_archived(self):
10241022
"Test searching for archived easyconfigs"

test/framework/robot.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1513,10 +1513,10 @@ def test_search_easyconfigs(self):
15131513

15141514
paths = search_easyconfigs('8-gcc', consider_extra_paths=False, print_result=False)
15151515
ref_paths = [
1516+
os.path.join(test_ecs, 'h', 'hwloc', 'hwloc-1.8-gcccuda-2018a.eb'),
15161517
os.path.join(test_ecs, 'h', 'hwloc', 'hwloc-1.11.8-GCC-4.6.4.eb'),
15171518
os.path.join(test_ecs, 'h', 'hwloc', 'hwloc-1.11.8-GCC-6.4.0-2.28.eb'),
15181519
os.path.join(test_ecs, 'h', 'hwloc', 'hwloc-1.11.8-GCC-7.3.0-2.30.eb'),
1519-
os.path.join(test_ecs, 'h', 'hwloc', 'hwloc-1.8-gcccuda-2018a.eb'),
15201520
os.path.join(test_ecs, 'o', 'OpenBLAS', 'OpenBLAS-0.2.8-GCC-4.8.2-LAPACK-3.4.2.eb')
15211521
]
15221522
self.assertEqual(paths, ref_paths)

0 commit comments

Comments
 (0)