Support os-specific $padding in config:install_tree
Providing only $padding or ${padding} results in an attempt to substitute a padding of maximum system path length, while leaving room for the parts of the install path spack generates. Providing $padding-<len> or ${padding-<len>} simply substitutes padding of the specified length.
This commit is contained in:
parent
ea818caca3
commit
47b3dda1aa
@ -23,7 +23,7 @@
|
||||
import spack.schema.mirrors
|
||||
import spack.schema.repos
|
||||
import spack.util.spack_yaml as syaml
|
||||
from spack.util.path import canonicalize_path
|
||||
import spack.util.path as spack_path
|
||||
|
||||
|
||||
# sample config data
|
||||
@ -272,31 +272,31 @@ def test_substitute_config_variables(mock_low_high_config):
|
||||
|
||||
assert os.path.join(
|
||||
'/foo/bar/baz', prefix
|
||||
) == canonicalize_path('/foo/bar/baz/$spack')
|
||||
) == spack_path.canonicalize_path('/foo/bar/baz/$spack')
|
||||
|
||||
assert os.path.join(
|
||||
spack.paths.prefix, 'foo/bar/baz'
|
||||
) == canonicalize_path('$spack/foo/bar/baz/')
|
||||
) == spack_path.canonicalize_path('$spack/foo/bar/baz/')
|
||||
|
||||
assert os.path.join(
|
||||
'/foo/bar/baz', prefix, 'foo/bar/baz'
|
||||
) == canonicalize_path('/foo/bar/baz/$spack/foo/bar/baz/')
|
||||
) == spack_path.canonicalize_path('/foo/bar/baz/$spack/foo/bar/baz/')
|
||||
|
||||
assert os.path.join(
|
||||
'/foo/bar/baz', prefix
|
||||
) == canonicalize_path('/foo/bar/baz/${spack}')
|
||||
) == spack_path.canonicalize_path('/foo/bar/baz/${spack}')
|
||||
|
||||
assert os.path.join(
|
||||
spack.paths.prefix, 'foo/bar/baz'
|
||||
) == canonicalize_path('${spack}/foo/bar/baz/')
|
||||
) == spack_path.canonicalize_path('${spack}/foo/bar/baz/')
|
||||
|
||||
assert os.path.join(
|
||||
'/foo/bar/baz', prefix, 'foo/bar/baz'
|
||||
) == canonicalize_path('/foo/bar/baz/${spack}/foo/bar/baz/')
|
||||
) == spack_path.canonicalize_path('/foo/bar/baz/${spack}/foo/bar/baz/')
|
||||
|
||||
assert os.path.join(
|
||||
'/foo/bar/baz', prefix, 'foo/bar/baz'
|
||||
) != canonicalize_path('/foo/bar/baz/${spack/foo/bar/baz/')
|
||||
) != spack_path.canonicalize_path('/foo/bar/baz/${spack/foo/bar/baz/')
|
||||
|
||||
|
||||
packages_merge_low = {
|
||||
@ -345,19 +345,43 @@ def test_merge_with_defaults(mock_low_high_config, write_config_file):
|
||||
|
||||
def test_substitute_user(mock_low_high_config):
|
||||
user = getpass.getuser()
|
||||
assert '/foo/bar/' + user + '/baz' == canonicalize_path(
|
||||
assert '/foo/bar/' + user + '/baz' == spack_path.canonicalize_path(
|
||||
'/foo/bar/$user/baz'
|
||||
)
|
||||
|
||||
|
||||
def test_substitute_tempdir(mock_low_high_config):
|
||||
tempdir = tempfile.gettempdir()
|
||||
assert tempdir == canonicalize_path('$tempdir')
|
||||
assert tempdir + '/foo/bar/baz' == canonicalize_path(
|
||||
assert tempdir == spack_path.canonicalize_path('$tempdir')
|
||||
assert tempdir + '/foo/bar/baz' == spack_path.canonicalize_path(
|
||||
'$tempdir/foo/bar/baz'
|
||||
)
|
||||
|
||||
|
||||
def test_substitute_padding(mock_low_high_config):
|
||||
max_system_path = spack_path.get_system_path_max()
|
||||
expected_length = (max_system_path -
|
||||
spack_path.SPACK_MAX_INSTALL_PATH_LENGTH)
|
||||
|
||||
install_path = spack_path.canonicalize_path('/foo/bar/${padding}/baz')
|
||||
|
||||
assert spack_path.SPACK_PATH_PADDING_CHARS in install_path
|
||||
assert len(install_path) == expected_length
|
||||
|
||||
install_path = spack_path.canonicalize_path('/foo/bar/baz/gah/$padding')
|
||||
|
||||
assert spack_path.SPACK_PATH_PADDING_CHARS in install_path
|
||||
assert len(install_path) == expected_length
|
||||
|
||||
i_path = spack_path.canonicalize_path('/foo/$padding:10')
|
||||
i_expect = os.path.join('/foo', spack_path.SPACK_PATH_PADDING_CHARS[:10])
|
||||
assert i_path == i_expect
|
||||
|
||||
i_path = spack_path.canonicalize_path('/foo/${padding:20}')
|
||||
i_expect = os.path.join('/foo', spack_path.SPACK_PATH_PADDING_CHARS[:20])
|
||||
assert i_path == i_expect
|
||||
|
||||
|
||||
def test_read_config(mock_low_high_config, write_config_file):
|
||||
write_config_file('config', config_low, 'low')
|
||||
assert spack.config.get('config') == config_low['config']
|
||||
|
@ -10,8 +10,12 @@
|
||||
import os
|
||||
import re
|
||||
import getpass
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.lang import memoized
|
||||
|
||||
import spack.paths
|
||||
|
||||
|
||||
@ -27,6 +31,38 @@
|
||||
'tempdir': tempfile.gettempdir(),
|
||||
}
|
||||
|
||||
# This is intended to be longer than the part of the install path
|
||||
# spack generates from the root path we give it. Included in the
|
||||
# estimate:
|
||||
#
|
||||
# os-arch -> 30
|
||||
# compiler -> 30
|
||||
# package name -> 50 (longest is currently 47 characters)
|
||||
# version -> 20
|
||||
# hash -> 32
|
||||
# buffer -> 138
|
||||
# ---------------------
|
||||
# total -> 300
|
||||
SPACK_MAX_INSTALL_PATH_LENGTH = 300
|
||||
SPACK_PATH_PADDING_CHARS = 'spack_path_placeholder'
|
||||
|
||||
|
||||
@memoized
|
||||
def get_system_path_max():
|
||||
# Choose a conservative default
|
||||
sys_max_path_length = 256
|
||||
try:
|
||||
path_max_proc = subprocess.Popen(['getconf', 'PATH_MAX', '/'],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
proc_output = str(path_max_proc.communicate()[0].decode())
|
||||
sys_max_path_length = int(proc_output)
|
||||
except (ValueError, subprocess.CalledProcessError, OSError):
|
||||
tty.msg('Unable to find system max path length, using: {0}'.format(
|
||||
sys_max_path_length))
|
||||
|
||||
return sys_max_path_length
|
||||
|
||||
|
||||
def substitute_config_variables(path):
|
||||
"""Substitute placeholders into paths.
|
||||
@ -58,8 +94,45 @@ def substitute_path_variables(path):
|
||||
return path
|
||||
|
||||
|
||||
def _get_padding_string(length):
|
||||
spack_path_padding_size = len(SPACK_PATH_PADDING_CHARS)
|
||||
num_reps = int(length / (spack_path_padding_size + 1))
|
||||
extra_chars = length % (spack_path_padding_size + 1)
|
||||
reps_list = [SPACK_PATH_PADDING_CHARS for i in range(num_reps)]
|
||||
reps_list.append(SPACK_PATH_PADDING_CHARS[:extra_chars])
|
||||
return os.path.sep.join(reps_list)
|
||||
|
||||
|
||||
def _add_computed_padding(path):
|
||||
"""Subtitute in padding of os-specific length. The intent is to leave
|
||||
SPACK_MAX_INSTALL_PATH_LENGTH characters available for parts of the
|
||||
path generated by spack. This is to allow for not-completely-known
|
||||
lengths of things like os/arch, compiler, package name, hash length,
|
||||
etc.
|
||||
"""
|
||||
padding_regex = re.compile(r'(\$[\w\d\:]+\b|\$\{[\w\d\:]+\})')
|
||||
m = padding_regex.search(path)
|
||||
if m and m.group(0).strip('${}').startswith('padding'):
|
||||
padding_part = m.group(0)
|
||||
len_pad_part = len(m.group(0))
|
||||
p_match = re.search(r'\:(\d+)', padding_part)
|
||||
if p_match:
|
||||
computed_padding = _get_padding_string(int(p_match.group(1)))
|
||||
else:
|
||||
# Take whatever has been computed/substituted so far and add some
|
||||
# room
|
||||
path_len = len(path) - len_pad_part + SPACK_MAX_INSTALL_PATH_LENGTH
|
||||
system_max_path = get_system_path_max()
|
||||
needed_pad_len = system_max_path - path_len
|
||||
computed_padding = _get_padding_string(needed_pad_len)
|
||||
return padding_regex.sub(computed_padding, path)
|
||||
return path
|
||||
|
||||
|
||||
def canonicalize_path(path):
|
||||
"""Same as substitute_path_variables, but also take absolute path."""
|
||||
path = substitute_path_variables(path)
|
||||
path = os.path.abspath(path)
|
||||
path = _add_computed_padding(path)
|
||||
|
||||
return path
|
||||
|
Loading…
Reference in New Issue
Block a user