Merge pull request #1026 from epfl-scitas/packages/lmod

lmod : updated package and dependencies
This commit is contained in:
Tom Scogland 2016-06-12 17:01:41 -07:00 committed by GitHub
commit 1b28991e0a
5 changed files with 139 additions and 151 deletions

View file

@ -43,7 +43,6 @@ def assert_ver_lt(self, a, b):
self.assertFalse(a > b) self.assertFalse(a > b)
self.assertFalse(a >= b) self.assertFalse(a >= b)
def assert_ver_gt(self, a, b): def assert_ver_gt(self, a, b):
a, b = ver(a), ver(b) a, b = ver(a), ver(b)
self.assertTrue(a > b) self.assertTrue(a > b)
@ -53,7 +52,6 @@ def assert_ver_gt(self, a, b):
self.assertFalse(a < b) self.assertFalse(a < b)
self.assertFalse(a <= b) self.assertFalse(a <= b)
def assert_ver_eq(self, a, b): def assert_ver_eq(self, a, b):
a, b = ver(a), ver(b) a, b = ver(a), ver(b)
self.assertFalse(a > b) self.assertFalse(a > b)
@ -63,55 +61,43 @@ def assert_ver_eq(self, a, b):
self.assertFalse(a < b) self.assertFalse(a < b)
self.assertTrue(a <= b) self.assertTrue(a <= b)
def assert_in(self, needle, haystack): def assert_in(self, needle, haystack):
self.assertTrue(ver(needle) in ver(haystack)) self.assertTrue(ver(needle) in ver(haystack))
def assert_not_in(self, needle, haystack): def assert_not_in(self, needle, haystack):
self.assertFalse(ver(needle) in ver(haystack)) self.assertFalse(ver(needle) in ver(haystack))
def assert_canonical(self, canonical_list, version_list): def assert_canonical(self, canonical_list, version_list):
self.assertEqual(ver(canonical_list), ver(version_list)) self.assertEqual(ver(canonical_list), ver(version_list))
def assert_overlaps(self, v1, v2): def assert_overlaps(self, v1, v2):
self.assertTrue(ver(v1).overlaps(ver(v2))) self.assertTrue(ver(v1).overlaps(ver(v2)))
def assert_no_overlap(self, v1, v2): def assert_no_overlap(self, v1, v2):
self.assertFalse(ver(v1).overlaps(ver(v2))) self.assertFalse(ver(v1).overlaps(ver(v2)))
def assert_satisfies(self, v1, v2): def assert_satisfies(self, v1, v2):
self.assertTrue(ver(v1).satisfies(ver(v2))) self.assertTrue(ver(v1).satisfies(ver(v2)))
def assert_does_not_satisfy(self, v1, v2): def assert_does_not_satisfy(self, v1, v2):
self.assertFalse(ver(v1).satisfies(ver(v2))) self.assertFalse(ver(v1).satisfies(ver(v2)))
def check_intersection(self, expected, a, b): def check_intersection(self, expected, a, b):
self.assertEqual(ver(expected), ver(a).intersection(ver(b))) self.assertEqual(ver(expected), ver(a).intersection(ver(b)))
def check_union(self, expected, a, b): def check_union(self, expected, a, b):
self.assertEqual(ver(expected), ver(a).union(ver(b))) self.assertEqual(ver(expected), ver(a).union(ver(b)))
def test_two_segments(self): def test_two_segments(self):
self.assert_ver_eq('1.0', '1.0') self.assert_ver_eq('1.0', '1.0')
self.assert_ver_lt('1.0', '2.0') self.assert_ver_lt('1.0', '2.0')
self.assert_ver_gt('2.0', '1.0') self.assert_ver_gt('2.0', '1.0')
def test_three_segments(self): def test_three_segments(self):
self.assert_ver_eq('2.0.1', '2.0.1') self.assert_ver_eq('2.0.1', '2.0.1')
self.assert_ver_lt('2.0', '2.0.1') self.assert_ver_lt('2.0', '2.0.1')
self.assert_ver_gt('2.0.1', '2.0') self.assert_ver_gt('2.0.1', '2.0')
def test_alpha(self): def test_alpha(self):
# TODO: not sure whether I like this. 2.0.1a is *usually* # TODO: not sure whether I like this. 2.0.1a is *usually*
# TODO: less than 2.0.1, but special-casing it makes version # TODO: less than 2.0.1, but special-casing it makes version
@ -120,7 +106,6 @@ def test_alpha(self):
self.assert_ver_gt('2.0.1a', '2.0.1') self.assert_ver_gt('2.0.1a', '2.0.1')
self.assert_ver_lt('2.0.1', '2.0.1a') self.assert_ver_lt('2.0.1', '2.0.1a')
def test_patch(self): def test_patch(self):
self.assert_ver_eq('5.5p1', '5.5p1') self.assert_ver_eq('5.5p1', '5.5p1')
self.assert_ver_lt('5.5p1', '5.5p2') self.assert_ver_lt('5.5p1', '5.5p2')
@ -129,7 +114,6 @@ def test_patch(self):
self.assert_ver_lt('5.5p1', '5.5p10') self.assert_ver_lt('5.5p1', '5.5p10')
self.assert_ver_gt('5.5p10', '5.5p1') self.assert_ver_gt('5.5p10', '5.5p1')
def test_num_alpha_with_no_separator(self): def test_num_alpha_with_no_separator(self):
self.assert_ver_lt('10xyz', '10.1xyz') self.assert_ver_lt('10xyz', '10.1xyz')
self.assert_ver_gt('10.1xyz', '10xyz') self.assert_ver_gt('10.1xyz', '10xyz')
@ -137,7 +121,6 @@ def test_num_alpha_with_no_separator(self):
self.assert_ver_lt('xyz10', 'xyz10.1') self.assert_ver_lt('xyz10', 'xyz10.1')
self.assert_ver_gt('xyz10.1', 'xyz10') self.assert_ver_gt('xyz10.1', 'xyz10')
def test_alpha_with_dots(self): def test_alpha_with_dots(self):
self.assert_ver_eq('xyz.4', 'xyz.4') self.assert_ver_eq('xyz.4', 'xyz.4')
self.assert_ver_lt('xyz.4', '8') self.assert_ver_lt('xyz.4', '8')
@ -145,30 +128,25 @@ def test_alpha_with_dots(self):
self.assert_ver_lt('xyz.4', '2') self.assert_ver_lt('xyz.4', '2')
self.assert_ver_gt('2', 'xyz.4') self.assert_ver_gt('2', 'xyz.4')
def test_nums_and_patch(self): def test_nums_and_patch(self):
self.assert_ver_lt('5.5p2', '5.6p1') self.assert_ver_lt('5.5p2', '5.6p1')
self.assert_ver_gt('5.6p1', '5.5p2') self.assert_ver_gt('5.6p1', '5.5p2')
self.assert_ver_lt('5.6p1', '6.5p1') self.assert_ver_lt('5.6p1', '6.5p1')
self.assert_ver_gt('6.5p1', '5.6p1') self.assert_ver_gt('6.5p1', '5.6p1')
def test_rc_versions(self): def test_rc_versions(self):
self.assert_ver_gt('6.0.rc1', '6.0') self.assert_ver_gt('6.0.rc1', '6.0')
self.assert_ver_lt('6.0', '6.0.rc1') self.assert_ver_lt('6.0', '6.0.rc1')
def test_alpha_beta(self): def test_alpha_beta(self):
self.assert_ver_gt('10b2', '10a1') self.assert_ver_gt('10b2', '10a1')
self.assert_ver_lt('10a2', '10b2') self.assert_ver_lt('10a2', '10b2')
def test_double_alpha(self): def test_double_alpha(self):
self.assert_ver_eq('1.0aa', '1.0aa') self.assert_ver_eq('1.0aa', '1.0aa')
self.assert_ver_lt('1.0a', '1.0aa') self.assert_ver_lt('1.0a', '1.0aa')
self.assert_ver_gt('1.0aa', '1.0a') self.assert_ver_gt('1.0aa', '1.0a')
def test_padded_numbers(self): def test_padded_numbers(self):
self.assert_ver_eq('10.0001', '10.0001') self.assert_ver_eq('10.0001', '10.0001')
self.assert_ver_eq('10.0001', '10.1') self.assert_ver_eq('10.0001', '10.1')
@ -176,24 +154,20 @@ def test_padded_numbers(self):
self.assert_ver_lt('10.0001', '10.0039') self.assert_ver_lt('10.0001', '10.0039')
self.assert_ver_gt('10.0039', '10.0001') self.assert_ver_gt('10.0039', '10.0001')
def test_close_numbers(self): def test_close_numbers(self):
self.assert_ver_lt('4.999.9', '5.0') self.assert_ver_lt('4.999.9', '5.0')
self.assert_ver_gt('5.0', '4.999.9') self.assert_ver_gt('5.0', '4.999.9')
def test_date_stamps(self): def test_date_stamps(self):
self.assert_ver_eq('20101121', '20101121') self.assert_ver_eq('20101121', '20101121')
self.assert_ver_lt('20101121', '20101122') self.assert_ver_lt('20101121', '20101122')
self.assert_ver_gt('20101122', '20101121') self.assert_ver_gt('20101122', '20101121')
def test_underscores(self): def test_underscores(self):
self.assert_ver_eq('2_0', '2_0') self.assert_ver_eq('2_0', '2_0')
self.assert_ver_eq('2.0', '2_0') self.assert_ver_eq('2.0', '2_0')
self.assert_ver_eq('2_0', '2.0') self.assert_ver_eq('2_0', '2.0')
def test_rpm_oddities(self): def test_rpm_oddities(self):
self.assert_ver_eq('1b.fc17', '1b.fc17') self.assert_ver_eq('1b.fc17', '1b.fc17')
self.assert_ver_lt('1b.fc17', '1.fc17') self.assert_ver_lt('1b.fc17', '1.fc17')
@ -202,7 +176,6 @@ def test_rpm_oddities(self):
self.assert_ver_gt('1g.fc17', '1.fc17') self.assert_ver_gt('1g.fc17', '1.fc17')
self.assert_ver_lt('1.fc17', '1g.fc17') self.assert_ver_lt('1.fc17', '1g.fc17')
# Stuff below here is not taken from RPM's tests and is # Stuff below here is not taken from RPM's tests and is
# unique to spack # unique to spack
def test_version_ranges(self): def test_version_ranges(self):
@ -214,7 +187,6 @@ def test_version_ranges(self):
self.assert_ver_lt('1.2:1.4', '1.5:1.6') self.assert_ver_lt('1.2:1.4', '1.5:1.6')
self.assert_ver_gt('1.5:1.6', '1.2:1.4') self.assert_ver_gt('1.5:1.6', '1.2:1.4')
def test_contains(self): def test_contains(self):
self.assert_in('1.3', '1.2:1.4') self.assert_in('1.3', '1.2:1.4')
self.assert_in('1.2.5', '1.2:1.4') self.assert_in('1.2.5', '1.2:1.4')
@ -233,7 +205,6 @@ def test_contains(self):
self.assert_in('1.4.1', '1.2.7:1.4') self.assert_in('1.4.1', '1.2.7:1.4')
self.assert_not_in('1.4.1', '1.2.7:1.4.0') self.assert_not_in('1.4.1', '1.2.7:1.4.0')
def test_in_list(self): def test_in_list(self):
self.assert_in('1.2', ['1.5', '1.2', '1.3']) self.assert_in('1.2', ['1.5', '1.2', '1.3'])
self.assert_in('1.2.5', ['1.5', '1.2:1.3']) self.assert_in('1.2.5', ['1.5', '1.2:1.3'])
@ -245,7 +216,6 @@ def test_in_list(self):
self.assert_not_in('1.2.5:1.5', ['1.5', '1.2:1.3']) self.assert_not_in('1.2.5:1.5', ['1.5', '1.2:1.3'])
self.assert_not_in('1.1:1.2.5', ['1.5', '1.2:1.3']) self.assert_not_in('1.1:1.2.5', ['1.5', '1.2:1.3'])
def test_ranges_overlap(self): def test_ranges_overlap(self):
self.assert_overlaps('1.2', '1.2') self.assert_overlaps('1.2', '1.2')
self.assert_overlaps('1.2.1', '1.2.1') self.assert_overlaps('1.2.1', '1.2.1')
@ -262,7 +232,6 @@ def test_ranges_overlap(self):
self.assert_overlaps(':', '1.6:1.9') self.assert_overlaps(':', '1.6:1.9')
self.assert_overlaps('1.6:1.9', ':') self.assert_overlaps('1.6:1.9', ':')
def test_overlap_with_containment(self): def test_overlap_with_containment(self):
self.assert_in('1.6.5', '1.6') self.assert_in('1.6.5', '1.6')
self.assert_in('1.6.5', ':1.6') self.assert_in('1.6.5', ':1.6')
@ -273,7 +242,6 @@ def test_overlap_with_containment(self):
self.assert_not_in(':1.6', '1.6.5') self.assert_not_in(':1.6', '1.6.5')
self.assert_in('1.6.5', ':1.6') self.assert_in('1.6.5', ':1.6')
def test_lists_overlap(self): def test_lists_overlap(self):
self.assert_overlaps('1.2b:1.7,5', '1.6:1.9,1') self.assert_overlaps('1.2b:1.7,5', '1.6:1.9,1')
self.assert_overlaps('1,2,3,4,5', '3,4,5,6,7') self.assert_overlaps('1,2,3,4,5', '3,4,5,6,7')
@ -287,7 +255,6 @@ def test_lists_overlap(self):
self.assert_no_overlap('1,2,3,4,5', '6,7') self.assert_no_overlap('1,2,3,4,5', '6,7')
self.assert_no_overlap('1,2,3,4,5', '6:7') self.assert_no_overlap('1,2,3,4,5', '6:7')
def test_canonicalize_list(self): def test_canonicalize_list(self):
self.assert_canonical(['1.2', '1.3', '1.4'], self.assert_canonical(['1.2', '1.3', '1.4'],
['1.2', '1.3', '1.3', '1.4']) ['1.2', '1.3', '1.3', '1.4'])
@ -316,7 +283,6 @@ def test_canonicalize_list(self):
self.assert_canonical([':'], self.assert_canonical([':'],
[':,1.3, 1.3.1,1.3.9,1.4 : 1.5 , 1.3 : 1.4']) [':,1.3, 1.3.1,1.3.9,1.4 : 1.5 , 1.3 : 1.4'])
def test_intersection(self): def test_intersection(self):
self.check_intersection('2.5', self.check_intersection('2.5',
'1.0:2.5', '2.5:3.0') '1.0:2.5', '2.5:3.0')
@ -325,12 +291,11 @@ def test_intersection(self):
self.check_intersection('0:1', ':', '0:1') self.check_intersection('0:1', ':', '0:1')
self.check_intersection(['1.0', '2.5:2.7'], self.check_intersection(['1.0', '2.5:2.7'],
['1.0:2.7'], ['2.5:3.0','1.0']) ['1.0:2.7'], ['2.5:3.0', '1.0'])
self.check_intersection(['2.5:2.7'], self.check_intersection(['2.5:2.7'],
['1.1:2.7'], ['2.5:3.0','1.0']) ['1.1:2.7'], ['2.5:3.0', '1.0'])
self.check_intersection(['0:1'], [':'], ['0:1']) self.check_intersection(['0:1'], [':'], ['0:1'])
def test_intersect_with_containment(self): def test_intersect_with_containment(self):
self.check_intersection('1.6.5', '1.6.5', ':1.6') self.check_intersection('1.6.5', '1.6.5', ':1.6')
self.check_intersection('1.6.5', ':1.6', '1.6.5') self.check_intersection('1.6.5', ':1.6', '1.6.5')
@ -338,7 +303,6 @@ def test_intersect_with_containment(self):
self.check_intersection('1.6:1.6.5', ':1.6.5', '1.6') self.check_intersection('1.6:1.6.5', ':1.6.5', '1.6')
self.check_intersection('1.6:1.6.5', '1.6', ':1.6.5') self.check_intersection('1.6:1.6.5', '1.6', ':1.6.5')
def test_union_with_containment(self): def test_union_with_containment(self):
self.check_union(':1.6', '1.6.5', ':1.6') self.check_union(':1.6', '1.6.5', ':1.6')
self.check_union(':1.6', ':1.6', '1.6.5') self.check_union(':1.6', ':1.6', '1.6.5')
@ -346,8 +310,6 @@ def test_union_with_containment(self):
self.check_union(':1.6', ':1.6.5', '1.6') self.check_union(':1.6', ':1.6.5', '1.6')
self.check_union(':1.6', '1.6', ':1.6.5') self.check_union(':1.6', '1.6', ':1.6.5')
def test_union_with_containment(self):
self.check_union(':', '1.0:', ':2.0') self.check_union(':', '1.0:', ':2.0')
self.check_union('1:4', '1:3', '2:4') self.check_union('1:4', '1:3', '2:4')
@ -356,7 +318,6 @@ def test_union_with_containment(self):
# Tests successor/predecessor case. # Tests successor/predecessor case.
self.check_union('1:4', '1:2', '3:4') self.check_union('1:4', '1:2', '3:4')
def test_basic_version_satisfaction(self): def test_basic_version_satisfaction(self):
self.assert_satisfies('4.7.3', '4.7.3') self.assert_satisfies('4.7.3', '4.7.3')
@ -372,7 +333,6 @@ def test_basic_version_satisfaction(self):
self.assert_does_not_satisfy('4.8', '4.9') self.assert_does_not_satisfy('4.8', '4.9')
self.assert_does_not_satisfy('4', '4.9') self.assert_does_not_satisfy('4', '4.9')
def test_basic_version_satisfaction_in_lists(self): def test_basic_version_satisfaction_in_lists(self):
self.assert_satisfies(['4.7.3'], ['4.7.3']) self.assert_satisfies(['4.7.3'], ['4.7.3'])
@ -388,7 +348,6 @@ def test_basic_version_satisfaction_in_lists(self):
self.assert_does_not_satisfy(['4.8'], ['4.9']) self.assert_does_not_satisfy(['4.8'], ['4.9'])
self.assert_does_not_satisfy(['4'], ['4.9']) self.assert_does_not_satisfy(['4'], ['4.9'])
def test_version_range_satisfaction(self): def test_version_range_satisfaction(self):
self.assert_satisfies('4.7b6', '4.3:4.7') self.assert_satisfies('4.7b6', '4.3:4.7')
self.assert_satisfies('4.3.0', '4.3:4.7') self.assert_satisfies('4.3.0', '4.3:4.7')
@ -400,7 +359,6 @@ def test_version_range_satisfaction(self):
self.assert_satisfies('4.7b6', '4.3:4.7') self.assert_satisfies('4.7b6', '4.3:4.7')
self.assert_does_not_satisfy('4.8.0', '4.3:4.7') self.assert_does_not_satisfy('4.8.0', '4.3:4.7')
def test_version_range_satisfaction_in_lists(self): def test_version_range_satisfaction_in_lists(self):
self.assert_satisfies(['4.7b6'], ['4.3:4.7']) self.assert_satisfies(['4.7b6'], ['4.3:4.7'])
self.assert_satisfies(['4.3.0'], ['4.3:4.7']) self.assert_satisfies(['4.3.0'], ['4.3:4.7'])
@ -423,3 +381,11 @@ def test_satisfaction_with_lists(self):
self.assert_satisfies('4.8.0', '4.2, 4.3:4.8') self.assert_satisfies('4.8.0', '4.2, 4.3:4.8')
self.assert_satisfies('4.8.2', '4.2, 4.3:4.8') self.assert_satisfies('4.8.2', '4.2, 4.3:4.8')
def test_formatted_strings(self):
versions = '1.2.3', '1_2_3', '1-2-3'
for item in versions:
v = Version(item)
self.assertEqual(v.dotted, '1.2.3')
self.assertEqual(v.dashed, '1-2-3')
self.assertEqual(v.underscored, '1_2_3')

View file

@ -43,16 +43,16 @@
intersection intersection
concrete concrete
""" """
import os
import sys
import re import re
from bisect import bisect_left from bisect import bisect_left
from functools import wraps from functools import wraps
from functools_backport import total_ordering from functools_backport import total_ordering
# Valid version characters # Valid version characters
VALID_VERSION = r'[A-Za-z0-9_.-]' VALID_VERSION = r'[A-Za-z0-9_.-]'
def int_if_int(string): def int_if_int(string):
"""Convert a string to int if possible. Otherwise, return a string.""" """Convert a string to int if possible. Otherwise, return a string."""
try: try:
@ -62,10 +62,11 @@ def int_if_int(string):
def coerce_versions(a, b): def coerce_versions(a, b):
"""Convert both a and b to the 'greatest' type between them, in this order: """
Convert both a and b to the 'greatest' type between them, in this order:
Version < VersionRange < VersionList Version < VersionRange < VersionList
This is used to simplify comparison operations below so that we're always This is used to simplify comparison operations below so that we're always
comparing things that are of the same type. comparing things that are of the same type.
""" """
order = (Version, VersionRange, VersionList) order = (Version, VersionRange, VersionList)
ta, tb = type(a), type(b) ta, tb = type(a), type(b)
@ -105,6 +106,7 @@ def coercing_method(a, b, *args, **kwargs):
@total_ordering @total_ordering
class Version(object): class Version(object):
"""Class to represent versions""" """Class to represent versions"""
def __init__(self, string): def __init__(self, string):
string = str(string) string = str(string)
@ -124,6 +126,17 @@ def __init__(self, string):
# last element of separators is '' # last element of separators is ''
self.separators = tuple(re.split(segment_regex, string)[1:-1]) self.separators = tuple(re.split(segment_regex, string)[1:-1])
@property
def dotted(self):
return '.'.join(str(x) for x in self.version)
@property
def underscored(self):
return '_'.join(str(x) for x in self.version)
@property
def dashed(self):
return '-'.join(str(x) for x in self.version)
def up_to(self, index): def up_to(self, index):
"""Return a version string up to the specified component, exclusive. """Return a version string up to the specified component, exclusive.
@ -131,15 +144,12 @@ def up_to(self, index):
""" """
return '.'.join(str(x) for x in self[:index]) return '.'.join(str(x) for x in self[:index])
def lowest(self): def lowest(self):
return self return self
def highest(self): def highest(self):
return self return self
@coerced @coerced
def satisfies(self, other): def satisfies(self, other):
"""A Version 'satisfies' another if it is at least as specific and has a """A Version 'satisfies' another if it is at least as specific and has a
@ -147,11 +157,10 @@ def satisfies(self, other):
gcc@4.7 so that when a user asks to build with gcc@4.7, we can find gcc@4.7 so that when a user asks to build with gcc@4.7, we can find
a suitable compiler. a suitable compiler.
""" """
nself = len(self.version) nself = len(self.version)
nother = len(other.version) nother = len(other.version)
return nother <= nself and self.version[:nother] == other.version return nother <= nself and self.version[:nother] == other.version
def wildcard(self): def wildcard(self):
"""Create a regex that will match variants of this version string.""" """Create a regex that will match variants of this version string."""
def a_or_n(seg): def a_or_n(seg):
@ -181,28 +190,22 @@ def a_or_n(seg):
wc += '(?:[a-z]|alpha|beta)?)?' * (len(segments) - 1) wc += '(?:[a-z]|alpha|beta)?)?' * (len(segments) - 1)
return wc return wc
def __iter__(self): def __iter__(self):
return iter(self.version) return iter(self.version)
def __getitem__(self, idx): def __getitem__(self, idx):
return tuple(self.version[idx]) return tuple(self.version[idx])
def __repr__(self): def __repr__(self):
return self.string return self.string
def __str__(self): def __str__(self):
return self.string return self.string
@property @property
def concrete(self): def concrete(self):
return self return self
@coerced @coerced
def __lt__(self, other): def __lt__(self, other):
"""Version comparison is designed for consistency with the way RPM """Version comparison is designed for consistency with the way RPM
@ -235,28 +238,23 @@ def __lt__(self, other):
# If the common prefix is equal, the one with more segments is bigger. # If the common prefix is equal, the one with more segments is bigger.
return len(self.version) < len(other.version) return len(self.version) < len(other.version)
@coerced @coerced
def __eq__(self, other): def __eq__(self, other):
return (other is not None and return (other is not None and
type(other) == Version and self.version == other.version) type(other) == Version and self.version == other.version)
def __ne__(self, other): def __ne__(self, other):
return not (self == other) return not (self == other)
def __hash__(self): def __hash__(self):
return hash(self.version) return hash(self.version)
@coerced @coerced
def __contains__(self, other): def __contains__(self, other):
if other is None: if other is None:
return False return False
return other.version[:len(self.version)] == self.version return other.version[:len(self.version)] == self.version
def is_predecessor(self, other): def is_predecessor(self, other):
"""True if the other version is the immediate predecessor of this one. """True if the other version is the immediate predecessor of this one.
That is, NO versions v exist such that: That is, NO versions v exist such that:
@ -269,16 +267,13 @@ def is_predecessor(self, other):
ol = other.version[-1] ol = other.version[-1]
return type(sl) == int and type(ol) == int and (ol - sl == 1) return type(sl) == int and type(ol) == int and (ol - sl == 1)
def is_successor(self, other): def is_successor(self, other):
return other.is_predecessor(self) return other.is_predecessor(self)
@coerced @coerced
def overlaps(self, other): def overlaps(self, other):
return self in other or other in self return self in other or other in self
@coerced @coerced
def union(self, other): def union(self, other):
if self == other or other in self: if self == other or other in self:
@ -288,7 +283,6 @@ def union(self, other):
else: else:
return VersionList([self, other]) return VersionList([self, other])
@coerced @coerced
def intersection(self, other): def intersection(self, other):
if self == other: if self == other:
@ -299,6 +293,7 @@ def intersection(self, other):
@total_ordering @total_ordering
class VersionRange(object): class VersionRange(object):
def __init__(self, start, end): def __init__(self, start, end):
if isinstance(start, basestring): if isinstance(start, basestring):
start = Version(start) start = Version(start)
@ -310,15 +305,12 @@ def __init__(self, start, end):
if start and end and end < start: if start and end and end < start:
raise ValueError("Invalid Version range: %s" % self) raise ValueError("Invalid Version range: %s" % self)
def lowest(self): def lowest(self):
return self.start return self.start
def highest(self): def highest(self):
return self.end return self.end
@coerced @coerced
def __lt__(self, other): def __lt__(self, other):
"""Sort VersionRanges lexicographically so that they are ordered first """Sort VersionRanges lexicographically so that they are ordered first
@ -331,28 +323,24 @@ def __lt__(self, other):
s, o = self, other s, o = self, other
if s.start != o.start: if s.start != o.start:
return s.start is None or (o.start is not None and s.start < o.start) return s.start is None or (o.start is not None and s.start < o.start) # NOQA: ignore=E501
return (s.end != o.end and return (s.end != o.end and
o.end is None or (s.end is not None and s.end < o.end)) o.end is None or (s.end is not None and s.end < o.end))
@coerced @coerced
def __eq__(self, other): def __eq__(self, other):
return (other is not None and return (other is not None and
type(other) == VersionRange and type(other) == VersionRange and
self.start == other.start and self.end == other.end) self.start == other.start and self.end == other.end)
def __ne__(self, other): def __ne__(self, other):
return not (self == other) return not (self == other)
@property @property
def concrete(self): def concrete(self):
return self.start if self.start == self.end else None return self.start if self.start == self.end else None
@coerced @coerced
def __contains__(self, other): def __contains__(self, other):
if other is None: if other is None:
@ -373,57 +361,55 @@ def __contains__(self, other):
other.end in self.end))) other.end in self.end)))
return in_upper return in_upper
@coerced @coerced
def satisfies(self, other): def satisfies(self, other):
"""A VersionRange satisfies another if some version in this range """
would satisfy some version in the other range. To do this it must A VersionRange satisfies another if some version in this range
either: would satisfy some version in the other range. To do this it must
a) Overlap with the other range either:
b) The start of this range satisfies the end of the other range. a) Overlap with the other range
b) The start of this range satisfies the end of the other range.
This is essentially the same as overlaps(), but overlaps assumes This is essentially the same as overlaps(), but overlaps assumes
that its arguments are specific. That is, 4.7 is interpreted as that its arguments are specific. That is, 4.7 is interpreted as
4.7.0.0.0.0... . This funciton assumes that 4.7 woudl be satisfied 4.7.0.0.0.0... . This funciton assumes that 4.7 woudl be satisfied
by 4.7.3.5, etc. by 4.7.3.5, etc.
Rationale: Rationale:
If a user asks for gcc@4.5:4.7, and a package is only compatible with If a user asks for gcc@4.5:4.7, and a package is only compatible with
gcc@4.7.3:4.8, then that package should be able to build under the gcc@4.7.3:4.8, then that package should be able to build under the
constraints. Just using overlaps() would not work here. constraints. Just using overlaps() would not work here.
Note that we don't need to check whether the end of this range Note that we don't need to check whether the end of this range
would satisfy the start of the other range, because overlaps() would satisfy the start of the other range, because overlaps()
already covers that case. already covers that case.
Note further that overlaps() is a symmetric operation, while Note further that overlaps() is a symmetric operation, while
satisfies() is not. satisfies() is not.
""" """
return (self.overlaps(other) or return (self.overlaps(other) or
# if either self.start or other.end are None, then this can't # if either self.start or other.end are None, then this can't
# satisfy, or overlaps() would've taken care of it. # satisfy, or overlaps() would've taken care of it.
self.start and other.end and self.start.satisfies(other.end)) self.start and other.end and self.start.satisfies(other.end))
@coerced @coerced
def overlaps(self, other): def overlaps(self, other):
return ((self.start == None or other.end is None or return ((self.start is None or other.end is None or
self.start <= other.end or self.start <= other.end or
other.end in self.start or self.start in other.end) and other.end in self.start or self.start in other.end) and
(other.start is None or self.end == None or (other.start is None or self.end is None or
other.start <= self.end or other.start <= self.end or
other.start in self.end or self.end in other.start)) other.start in self.end or self.end in other.start))
@coerced @coerced
def union(self, other): def union(self, other):
if not self.overlaps(other): if not self.overlaps(other):
if (self.end is not None and other.start is not None and if (self.end is not None and other.start is not None and
self.end.is_predecessor(other.start)): self.end.is_predecessor(other.start)):
return VersionRange(self.start, other.end) return VersionRange(self.start, other.end)
if (other.end is not None and self.start is not None and if (other.end is not None and self.start is not None and
other.end.is_predecessor(self.start)): other.end.is_predecessor(self.start)):
return VersionRange(other.start, self.end) return VersionRange(other.start, self.end)
return VersionList([self, other]) return VersionList([self, other])
@ -442,13 +428,12 @@ def union(self, other):
else: else:
end = self.end end = self.end
# TODO: See note in intersection() about < and in discrepancy. # TODO: See note in intersection() about < and in discrepancy.
if not other.end in self.end: if other.end not in self.end:
if end in other.end or other.end > self.end: if end in other.end or other.end > self.end:
end = other.end end = other.end
return VersionRange(start, end) return VersionRange(start, end)
@coerced @coerced
def intersection(self, other): def intersection(self, other):
if self.overlaps(other): if self.overlaps(other):
@ -470,7 +455,7 @@ def intersection(self, other):
# 1.6 < 1.6.5 = True (lexicographic) # 1.6 < 1.6.5 = True (lexicographic)
# Should 1.6 NOT be less than 1.6.5? Hm. # Should 1.6 NOT be less than 1.6.5? Hm.
# Here we test (not end in other.end) first to avoid paradox. # Here we test (not end in other.end) first to avoid paradox.
if other.end is not None and not end in other.end: if other.end is not None and end not in other.end:
if other.end < end or other.end in end: if other.end < end or other.end in end:
end = other.end end = other.end
@ -479,15 +464,12 @@ def intersection(self, other):
else: else:
return VersionList() return VersionList()
def __hash__(self): def __hash__(self):
return hash((self.start, self.end)) return hash((self.start, self.end))
def __repr__(self): def __repr__(self):
return self.__str__() return self.__str__()
def __str__(self): def __str__(self):
out = "" out = ""
if self.start: if self.start:
@ -501,6 +483,7 @@ def __str__(self):
@total_ordering @total_ordering
class VersionList(object): class VersionList(object):
"""Sorted, non-redundant list of Versions and VersionRanges.""" """Sorted, non-redundant list of Versions and VersionRanges."""
def __init__(self, vlist=None): def __init__(self, vlist=None):
self.versions = [] self.versions = []
if vlist is not None: if vlist is not None:
@ -515,7 +498,6 @@ def __init__(self, vlist=None):
for v in vlist: for v in vlist:
self.add(ver(v)) self.add(ver(v))
def add(self, version): def add(self, version):
if type(version) in (Version, VersionRange): if type(version) in (Version, VersionRange):
# This normalizes single-value version ranges. # This normalizes single-value version ranges.
@ -524,9 +506,9 @@ def add(self, version):
i = bisect_left(self, version) i = bisect_left(self, version)
while i-1 >= 0 and version.overlaps(self[i-1]): while i - 1 >= 0 and version.overlaps(self[i - 1]):
version = version.union(self[i-1]) version = version.union(self[i - 1])
del self.versions[i-1] del self.versions[i - 1]
i -= 1 i -= 1
while i < len(self) and version.overlaps(self[i]): while i < len(self) and version.overlaps(self[i]):
@ -542,7 +524,6 @@ def add(self, version):
else: else:
raise TypeError("Can't add %s to VersionList" % type(version)) raise TypeError("Can't add %s to VersionList" % type(version))
@property @property
def concrete(self): def concrete(self):
if len(self) == 1: if len(self) == 1:
@ -550,11 +531,9 @@ def concrete(self):
else: else:
return None return None
def copy(self): def copy(self):
return VersionList(self) return VersionList(self)
def lowest(self): def lowest(self):
"""Get the lowest version in the list.""" """Get the lowest version in the list."""
if not self: if not self:
@ -562,7 +541,6 @@ def lowest(self):
else: else:
return self[0].lowest() return self[0].lowest()
def highest(self): def highest(self):
"""Get the highest version in the list.""" """Get the highest version in the list."""
if not self: if not self:
@ -570,7 +548,6 @@ def highest(self):
else: else:
return self[-1].highest() return self[-1].highest()
@coerced @coerced
def overlaps(self, other): def overlaps(self, other):
if not other or not self: if not other or not self:
@ -586,14 +563,12 @@ def overlaps(self, other):
o += 1 o += 1
return False return False
def to_dict(self): def to_dict(self):
"""Generate human-readable dict for YAML.""" """Generate human-readable dict for YAML."""
if self.concrete: if self.concrete:
return { 'version' : str(self[0]) } return {'version': str(self[0])}
else: else:
return { 'versions' : [str(v) for v in self] } return {'versions': [str(v) for v in self]}
@staticmethod @staticmethod
def from_dict(dictionary): def from_dict(dictionary):
@ -605,7 +580,6 @@ def from_dict(dictionary):
else: else:
raise ValueError("Dict must have 'version' or 'versions' in it.") raise ValueError("Dict must have 'version' or 'versions' in it.")
@coerced @coerced
def satisfies(self, other, strict=False): def satisfies(self, other, strict=False):
"""A VersionList satisfies another if some version in the list """A VersionList satisfies another if some version in the list
@ -633,20 +607,17 @@ def satisfies(self, other, strict=False):
o += 1 o += 1
return False return False
@coerced @coerced
def update(self, other): def update(self, other):
for v in other.versions: for v in other.versions:
self.add(v) self.add(v)
@coerced @coerced
def union(self, other): def union(self, other):
result = self.copy() result = self.copy()
result.update(other) result.update(other)
return result return result
@coerced @coerced
def intersection(self, other): def intersection(self, other):
# TODO: make this faster. This is O(n^2). # TODO: make this faster. This is O(n^2).
@ -656,7 +627,6 @@ def intersection(self, other):
result.add(s.intersection(o)) result.add(s.intersection(o))
return result return result
@coerced @coerced
def intersect(self, other): def intersect(self, other):
"""Intersect this spec's list with other. """Intersect this spec's list with other.
@ -678,50 +648,40 @@ def __contains__(self, other):
if i == 0: if i == 0:
if version not in self[0]: if version not in self[0]:
return False return False
elif all(version not in v for v in self[i-1:]): elif all(version not in v for v in self[i - 1:]):
return False return False
return True return True
def __getitem__(self, index): def __getitem__(self, index):
return self.versions[index] return self.versions[index]
def __iter__(self): def __iter__(self):
return iter(self.versions) return iter(self.versions)
def __reversed__(self): def __reversed__(self):
return reversed(self.versions) return reversed(self.versions)
def __len__(self): def __len__(self):
return len(self.versions) return len(self.versions)
@coerced @coerced
def __eq__(self, other): def __eq__(self, other):
return other is not None and self.versions == other.versions return other is not None and self.versions == other.versions
def __ne__(self, other): def __ne__(self, other):
return not (self == other) return not (self == other)
@coerced @coerced
def __lt__(self, other): def __lt__(self, other):
return other is not None and self.versions < other.versions return other is not None and self.versions < other.versions
def __hash__(self): def __hash__(self):
return hash(tuple(self.versions)) return hash(tuple(self.versions))
def __str__(self): def __str__(self):
return ",".join(str(v) for v in self.versions) return ",".join(str(v) for v in self.versions)
def __repr__(self): def __repr__(self):
return str(self.versions) return str(self.versions)
@ -730,7 +690,7 @@ def _string_to_version(string):
"""Converts a string to a Version, VersionList, or VersionRange. """Converts a string to a Version, VersionList, or VersionRange.
This is private. Client code should use ver(). This is private. Client code should use ver().
""" """
string = string.replace(' ','') string = string.replace(' ', '')
if ',' in string: if ',' in string:
return VersionList(string.split(',')) return VersionList(string.split(','))
@ -738,7 +698,7 @@ def _string_to_version(string):
elif ':' in string: elif ':' in string:
s, e = string.split(':') s, e = string.split(':')
start = Version(s) if s else None start = Version(s) if s else None
end = Version(e) if e else None end = Version(e) if e else None
return VersionRange(start, end) return VersionRange(start, end)
else: else:

View file

@ -23,7 +23,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
############################################################################## ##############################################################################
from spack import * from spack import *
import os
class Lmod(Package): class Lmod(Package):
""" """
@ -34,17 +34,25 @@ class Lmod(Package):
variable. Modulefiles for Library packages provide environment variables variable. Modulefiles for Library packages provide environment variables
that specify where the library and header files can be found. that specify where the library and header files can be found.
""" """
homepage = "https://www.tacc.utexas.edu/research-development/tacc-projects/lmod" homepage = 'https://www.tacc.utexas.edu/research-development/tacc-projects/lmod' # NOQA: ignore=E501
url = "http://sourceforge.net/projects/lmod/files/Lmod-6.0.1.tar.bz2/download" url = 'https://github.com/TACC/Lmod/archive/6.4.1.tar.gz'
version('6.4.1', '7978ba777c8aa41a4d8c05fec5f780f4')
version('6.3.7', '0fa4d5a24c41cae03776f781aa2dedc1')
version('6.0.1', '91abf52fe5033bd419ffe2842ebe7af9') version('6.0.1', '91abf52fe5033bd419ffe2842ebe7af9')
depends_on("lua@5.2:") depends_on('lua@5.2:')
depends_on('lua-luaposix')
depends_on('lua-luafilesystem')
parallel = False
def setup_environment(self, spack_env, run_env):
stage_lua_path = join_path(
self.stage.path, 'Lmod-{version}', 'src', '?.lua')
spack_env.append_path('LUA_PATH', stage_lua_path.format(
version=self.version), separator=';')
def install(self, spec, prefix): def install(self, spec, prefix):
# Add our lua to PATH
os.environ['PATH'] = spec['lua'].prefix.bin + ';' + os.environ['PATH']
configure('--prefix=%s' % prefix) configure('--prefix=%s' % prefix)
make() make('install')
make("install")

View file

@ -0,0 +1,51 @@
##############################################################################
# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC.
# Produced at the Lawrence Livermore National Laboratory.
#
# This file is part of Spack.
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
# LLNL-CODE-647188
#
# For details, see https://github.com/llnl/spack
# Please also see the LICENSE file for our notice and the LGPL.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License (as
# published by the Free Software Foundation) version 2.1, February 1999.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
# conditions of the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
from spack import *
class LuaLuafilesystem(Package):
"""
LuaFileSystem is a Lua library developed to complement the set of
functions related to file systems offered by the standard Lua distribution.
LuaFileSystem offers a portable way to access the underlying directory
structure and file attributes.
LuaFileSystem is free software and uses the same license as Lua 5.1
"""
homepage = 'http://keplerproject.github.io/luafilesystem'
url = 'https://github.com/keplerproject/luafilesystem/archive/v_1_6_3.tar.gz'
version('1_6_3', 'd0552c7e5a082f5bb2865af63fb9dc95')
extends('lua')
def install(self, spec, prefix):
rockspec_fmt = join_path(self.stage.path,
'luafilesystem-v_{version.underscored}',
'rockspecs',
'luafilesystem-{version.dotted}-1.rockspec')
luarocks('--tree=' + prefix, 'install',
rockspec_fmt.format(version=self.spec.version))

View file

@ -57,7 +57,7 @@ class Lua(Package):
placement='luarocks') placement='luarocks')
def install(self, spec, prefix): def install(self, spec, prefix):
if spec.satisfies("arch=darwin-i686") or spec.satisfies("arch=darwin-x86_64"): if spec.satisfies("arch=darwin-i686") or spec.satisfies("arch=darwin-x86_64"): # NOQA: ignore=E501
target = 'macosx' target = 'macosx'
else: else:
target = 'linux' target = 'linux'
@ -105,6 +105,9 @@ def setup_dependent_environment(self, spack_env, run_env, extension_spec):
spack_env.set('LUA_PATH', ';'.join(lua_patterns), separator=';') spack_env.set('LUA_PATH', ';'.join(lua_patterns), separator=';')
spack_env.set('LUA_CPATH', ';'.join(lua_cpatterns), separator=';') spack_env.set('LUA_CPATH', ';'.join(lua_cpatterns), separator=';')
# Add LUA to PATH for dependent packages
spack_env.prepend_path('PATH', self.prefix.bin)
# For run time environment set only the path for extension_spec and # For run time environment set only the path for extension_spec and
# prepend it to LUAPATH # prepend it to LUAPATH
if extension_spec.package.extends(self.spec): if extension_spec.package.extends(self.spec):
@ -153,5 +156,5 @@ def setup_dependent_package(self, module, ext_spec):
""" """
# Lua extension builds can have lua and luarocks executable functions # Lua extension builds can have lua and luarocks executable functions
module.lua = Executable(join_path(self.spec.prefix.bin, 'lua')) module.lua = Executable(join_path(self.spec.prefix.bin, 'lua'))
module.luarocks = Executable(join_path(self.spec.prefix.bin, module.luarocks = Executable(
'luarocks')) join_path(self.spec.prefix.bin, 'luarocks'))