# Copyright 2024 The Bazel Authors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Substitute environment variables in shell format strings.""" def envsubst(template_string, varnames, getenv): """Helper function to substitute environment variables. Supports `$VARNAME`, `${VARNAME}` and `${VARNAME:-default}` syntaxes in the `template_string`, looking up each `VARNAME` listed in the `varnames` list in the environment defined by the `getenv` function. Typically called with `getenv = rctx.getenv` (if it is available) or `getenv = rctx.os.environ.get` (on e.g. Bazel 6 or Bazel 7, which don't have `rctx.getenv` yet). Limitations: Unlike the shell, we don't support `${VARNAME}` and `${VARNAME:-default}` in the default expression for a different environment variable expansion. We do support the braceless syntax in the default, so an expression such as `${HOME:-/home/$USER}` is valid. Args: template_string: String that may contain variables to be expanded. varnames: List of variable names of variables to expand in `template_string`. getenv: Callable mapping variable names (in the first argument) to their values, or returns the default (provided in the second argument to `getenv`) if a value wasn't found. Returns: `template_string` with environment variables expanded according to their values as determined by `getenv`. """ if not varnames: return template_string for varname in varnames: value = getenv(varname, "") template_string = template_string.replace("$%s" % varname, value) template_string = template_string.replace("${%s}" % varname, value) segments = template_string.split("${%s:-" % varname) template_string = segments.pop(0) for segment in segments: default_value, separator, rest = segment.partition("}") if "{" in default_value: fail("Environment substitution expression " + "\"${%s:-\" has an opening \"{\" " % varname + "in default value \"%s\"." % default_value) if not separator: fail("Environment substitution expression " + "\"${%s:-\" is missing the final \"}\"" % varname) template_string += (value if value else default_value) + rest return template_string