# SPDX-License-Identifier: Apache-2.0
# Copyright Contributors to the Rez Project
"""
Utility code for supporting earlier Rez data in later Rez releases.
"""
import re
import os
import os.path
import textwrap
variant_key_conversions = {
"name": "name",
"version": "version",
"index": "index",
"search_path": "location"
}
[docs]def convert_old_variant_handle(handle_dict):
"""Convert a variant handle from serialize_version < 4.0."""
old_variables = handle_dict.get("variables", {})
variables = dict(repository_type="filesystem")
for old_key, key in variant_key_conversions.items():
value = old_variables.get(old_key)
variables[key] = value
path = handle_dict["path"]
filename = os.path.basename(path)
if os.path.splitext(filename)[0] == "package":
key = "filesystem.variant"
else:
key = "filesystem.variant.combined"
return dict(key=key, variables=variables)
[docs]def convert_old_command_expansions(command):
"""Convert expansions from !OLD! style to {new}."""
command = command.replace("!VERSION!", "{version}")
command = command.replace("!MAJOR_VERSION!", "{version.major}")
command = command.replace("!MINOR_VERSION!", "{version.minor}")
command = command.replace("!BASE!", "{base}")
command = command.replace("!ROOT!", "{root}")
command = command.replace("!USER!", "{system.user}")
return command
within_unescaped_quotes_regex = re.compile('(?<!\\\\)"(.*?)(?<!\\\\)"')
[docs]def convert_old_commands(commands, annotate=True):
"""Converts old-style package commands into equivalent Rex code."""
from rez.config import config
from rez.utils.logging_ import print_debug
def _repl(s):
return s.replace('\\"', '"')
def _encode(s):
# this replaces all occurrances of '\"' with '"', *except* for those
# occurrances of '\"' that are within double quotes, which themselves
# are not escaped. In other words, the string:
# 'hey "there \"you\" " \"dude\" '
# ..will convert to:
# 'hey "there \"you\" " "dude" '
s_new = ''
prev_i = 0
for m in within_unescaped_quotes_regex.finditer(s):
s_ = s[prev_i:m.start()]
s_new += _repl(s_)
s_new += s[m.start():m.end()]
prev_i = m.end()
s_ = s[prev_i:]
s_new += _repl(s_)
return repr(s_new)
loc = []
for cmd in commands:
if annotate:
txt = "OLD COMMAND: %s" % cmd
line = "comment(%s)" % _encode(txt)
loc.append(line)
cmd = convert_old_command_expansions(cmd)
toks = cmd.strip().split()
try:
if toks[0] == "export":
var, value = cmd.split(' ', 1)[1].split('=', 1)
for bookend in ('"', "'"):
if value.startswith(bookend) and value.endswith(bookend):
value = value[1:-1]
break
# As the only old-style commands were Linux/Bash based,
# we assume using the default separator ":" is ok - we don't
# need to use os.pathsep as we don't expected to see a
# Windows path here.
separator = config.env_var_separators.get(var, ":")
# This is a special case. We don't want to include "';'" in
# our env var separators map as it's not really the correct
# behaviour/something we want to promote. It's included here for
# backwards compatibility only, and to not propogate elsewhere.
if var == "CMAKE_MODULE_PATH":
value = value.replace("'%s'" % separator, separator)
value = value.replace('"%s"' % separator, separator)
value = value.replace(":", separator)
parts = value.split(separator)
parts = [x for x in parts if x]
if len(parts) > 1:
idx = None
var1 = "$%s" % var
var2 = "${%s}" % var
if var1 in parts:
idx = parts.index(var1)
elif var2 in parts:
idx = parts.index(var2)
if idx in (0, len(parts) - 1):
func = "appendenv" if idx == 0 else "prependenv"
parts = parts[1:] if idx == 0 else parts[:-1]
val = separator.join(parts)
loc.append("%s('%s', %s)" % (func, var, _encode(val)))
continue
loc.append("setenv('%s', %s)" % (var, _encode(value)))
elif toks[0].startswith('#'):
loc.append("comment(%s)" % _encode(' '.join(toks[1:])))
elif toks[0] == "alias":
match = re.search("alias (?P<key>.*?)=(?P<value>.*)", cmd)
key = match.groupdict()['key'].strip()
value = match.groupdict()['value'].strip()
if (value.startswith('"') and value.endswith('"')) or \
(value.startswith("'") and value.endswith("'")):
value = value[1:-1]
loc.append("alias('%s', %s)" % (key, _encode(value)))
else:
# assume we can execute this as a straight command
loc.append("command(%s)" % _encode(cmd))
except:
# if anything goes wrong, just fall back to bash command
loc.append("command(%s)" % _encode(cmd))
rex_code = '\n'.join(loc)
if config.debug("old_commands"):
br = '-' * 80
msg = textwrap.dedent(
"""
%s
OLD COMMANDS:
%s
NEW COMMANDS:
%s
%s
""") % (br, '\n'.join(commands), rex_code, br)
print_debug(msg)
return rex_code