diff --git a/CONSTRUCT.md b/CONSTRUCT.md index f4ce1b18c..13d88f78d 100644 --- a/CONSTRUCT.md +++ b/CONSTRUCT.md @@ -380,6 +380,30 @@ _type:_ string
Application name in the Windows "Programs and Features" control panel. Defaults to `${NAME} ${VERSION} (Python ${PYVERSION} ${ARCH})`. +### `script_env_variables` + +_required:_ no
+_type:_ dictionary
+ +Dictionary of additional environment variables to be made available to +the pre_install and post_install scripts, in the form of VAR:VALUE +pairs. These environment variables are in addition to those in the +`post_install` section above and take precedence in the case of name +collisions. + +On Unix the variable values are automatically single quoted, allowing +you to supply strings with spaces, without needing to worry about +escaping. As a consequence, string interpolation is disabled: if you +need string interpolation, you can apply it in the +pre_install/post_install script(s). If you need to include single quotes +in your value, you can escape them by replacing each single quote with +`'''`. + +On Windows, single quotes and double quotes are not supported. + +Note that the # (hash) character cannot be used as it denotes yaml +comments for all platforms. + ### `pre_install` _required:_ no
diff --git a/constructor/construct.py b/constructor/construct.py index f386ff4b0..26e3f91aa 100644 --- a/constructor/construct.py +++ b/constructor/construct.py @@ -271,6 +271,26 @@ Defaults to `${NAME} ${VERSION} (Python ${PYVERSION} ${ARCH})`. '''), + ('script_env_variables', False, (dict,), ''' +Dictionary of additional environment variables to be made available to +the pre_install and post_install scripts, in the form of VAR:VALUE +pairs. These environment variables are in addition to those in the +`post_install` section above and take precedence in the case of name +collisions. + +On Unix the variable values are automatically single quoted, allowing +you to supply strings with spaces, without needing to worry about +escaping. As a consequence, string interpolation is disabled: if you +need string interpolation, you can apply it in the +pre_install/post_install script(s). If you need to include single quotes +in your value, you can escape them by replacing each single quote with +`'\''`. + +On Windows, single quotes and double quotes are not supported. + +Note that the # (hash) character cannot be used as it denotes yaml +comments for all platforms. +'''), ('pre_install', False, str, ''' Path to a pre-install script, run after the package cache has been set, but before the files are linked to their final locations. As a result, you should diff --git a/constructor/header.sh b/constructor/header.sh index 942ceee3e..b8db07aa2 100644 --- a/constructor/header.sh +++ b/constructor/header.sh @@ -23,6 +23,8 @@ fi # Export variables to make installer metadata available to pre/post install scripts # NOTE: If more vars are added, make sure to update the examples/scripts tests too + +_SCRIPT_ENV_VARIABLES_='' # Templated extra environment variable(s) export INSTALLER_NAME='__NAME__' export INSTALLER_VER='__VERSION__' export INSTALLER_PLAT='__PLAT__' diff --git a/constructor/nsis/main.nsi.tmpl b/constructor/nsis/main.nsi.tmpl index c4897dac4..a2ae2fb28 100644 --- a/constructor/nsis/main.nsi.tmpl +++ b/constructor/nsis/main.nsi.tmpl @@ -1113,6 +1113,7 @@ Section "Install" File /nonfatal /r __INDEX_CACHE__ File /r __REPODATA_RECORD__ + @SCRIPT_ENV_VARIABLES@ System::Call 'kernel32::SetEnvironmentVariable(t,t)i("CONDA_SAFETY_CHECKS", "disabled").r0' System::Call 'kernel32::SetEnvironmentVariable(t,t)i("CONDA_EXTRA_SAFETY_CHECKS", "no").r0' System::Call 'kernel32::SetEnvironmentVariable(t,t)i("CONDA_PKGS_DIRS", "$INSTDIR\pkgs")".r0' diff --git a/constructor/osx/run_user_script.sh b/constructor/osx/run_user_script.sh index 53bd4501a..9f6291518 100644 --- a/constructor/osx/run_user_script.sh +++ b/constructor/osx/run_user_script.sh @@ -31,6 +31,7 @@ export INSTALLER_VER="__VERSION__" export INSTALLER_PLAT="__PLAT__" export INSTALLER_TYPE="PKG" export PRE_OR_POST="__PRE_OR_POST__" +_SCRIPT_ENV_VARIABLES_='' # Templated extra environment variable(s) # Run user-provided script if [ -f "$PREFIX/pkgs/user_${PRE_OR_POST}" ]; then diff --git a/constructor/osxpkg.py b/constructor/osxpkg.py index 64840c80e..22213a596 100644 --- a/constructor/osxpkg.py +++ b/constructor/osxpkg.py @@ -308,8 +308,12 @@ def move_script(src, dst, info, ensure_shebang=False, user_script_type=None): 'CONSTRUCTOR_VERSION': info['CONSTRUCTOR_VERSION'], } data = preprocess(data, ppd) + custom_variables = info.get('script_env_variables', {}) data = fill_template(data, replace) + data = data.replace("_SCRIPT_ENV_VARIABLES_=''", '\n'.join( + [f"export {key}='{value}'" for key, value in custom_variables.items()])) + with open(dst, 'w') as fo: if ( ensure_shebang diff --git a/constructor/shar.py b/constructor/shar.py index 9d08fe2a6..178372075 100644 --- a/constructor/shar.py +++ b/constructor/shar.py @@ -92,8 +92,11 @@ def get_header(conda_exec, tarball, info): data = read_header_template() data = preprocess(data, ppd) + custom_variables = info.get('script_env_variables', {}) data = fill_template(data, replace) + data = data.replace("_SCRIPT_ENV_VARIABLES_=''", '\n'.join( + [f"export {key}='{value}'" for key, value in custom_variables.items()])) return data diff --git a/constructor/winexe.py b/constructor/winexe.py index 345378ce7..3e22a9485 100644 --- a/constructor/winexe.py +++ b/constructor/winexe.py @@ -87,6 +87,23 @@ def insert_tempfiles_commands(paths: os.PathLike) -> List[str]: return lines +def setup_script_env_variables(info) -> List[str]: + """Helper function to insert extra environment variables into nsis template. + + Args: + info: Dictionary of information parsed from construct.yaml + + Returns: + List[str]: Commands to be inserted into nsi template + """ + lines = [] + for name, value in info.get('script_env_variables', {}).items(): + lines.append( + "System::Call 'kernel32::SetEnvironmentVariable(t,t)i" + + f"""("{name}", {str_esc(value)}).r0'""") + return lines + + def custom_nsi_insert_from_file(filepath: os.PathLike) -> str: """Insert NSI script commands from file. @@ -332,6 +349,7 @@ def make_nsi(info, dir_path, extra_files=None, temp_extra_files=None): '${NAME} ${VERSION} (Python ${PYVERSION} ${ARCH})' )), ('@EXTRA_FILES@', '\n '.join(extra_files_commands(extra_files, dir_path))), + ('@SCRIPT_ENV_VARIABLES@', '\n '.join(setup_script_env_variables(info))), ( '@CUSTOM_WELCOME_FILE@', custom_nsi_insert_from_file(info.get('welcome_file', '')) diff --git a/docs/source/construct-yaml.md b/docs/source/construct-yaml.md index f4ce1b18c..13d88f78d 100644 --- a/docs/source/construct-yaml.md +++ b/docs/source/construct-yaml.md @@ -380,6 +380,30 @@ _type:_ string
Application name in the Windows "Programs and Features" control panel. Defaults to `${NAME} ${VERSION} (Python ${PYVERSION} ${ARCH})`. +### `script_env_variables` + +_required:_ no
+_type:_ dictionary
+ +Dictionary of additional environment variables to be made available to +the pre_install and post_install scripts, in the form of VAR:VALUE +pairs. These environment variables are in addition to those in the +`post_install` section above and take precedence in the case of name +collisions. + +On Unix the variable values are automatically single quoted, allowing +you to supply strings with spaces, without needing to worry about +escaping. As a consequence, string interpolation is disabled: if you +need string interpolation, you can apply it in the +pre_install/post_install script(s). If you need to include single quotes +in your value, you can escape them by replacing each single quote with +`'''`. + +On Windows, single quotes and double quotes are not supported. + +Note that the # (hash) character cannot be used as it denotes yaml +comments for all platforms. + ### `pre_install` _required:_ no
diff --git a/examples/scripts/construct.yaml b/examples/scripts/construct.yaml index 97d64e197..e57bdffa0 100644 --- a/examples/scripts/construct.yaml +++ b/examples/scripts/construct.yaml @@ -5,6 +5,14 @@ channels: - http://repo.anaconda.com/pkgs/main/ specs: - python + +script_env_variables: + CUSTOM_VARIABLE_1: FIR$T-CUSTOM_'\''STRING'\'' WITH SPACES AND @*! "CHARACTERS" # [not win] + CUSTOM_VARIABLE_2: $ECOND-CUSTOM_'\''STRING'\'' WITH SPACES AND @*! "CHARACTERS" # [not win] + CUSTOM_VARIABLE_1: FIR$T-CUSTOM_STRING WITH SPACES AND @*! CHARACTERS # [win] + CUSTOM_VARIABLE_2: $ECOND-CUSTOM_STRING WITH SPACES AND @*! CHARACTERS # [win] + + pre_install: pre_install.sh # [unix] pre_install: pre_install.bat # [win] pre_install_desc: "Adding this description makes the script selectable in the UI" diff --git a/examples/scripts/post_install.bat b/examples/scripts/post_install.bat index 6b80f986a..7a435cafc 100644 --- a/examples/scripts/post_install.bat +++ b/examples/scripts/post_install.bat @@ -4,4 +4,6 @@ if not "%INSTALLER_VER%" == "X" exit 1 if not "%INSTALLER_PLAT%" == "win-64" exit 1 if not "%INSTALLER_TYPE%" == "EXE" exit 1 if "%PREFIX%" == "" exit 1 +if not "%CUSTOM_VARIABLE_1%" == "FIR$T-CUSTOM_STRING WITH SPACES AND @*! CHARACTERS" exit 1 +if not "%CUSTOM_VARIABLE_2%" == "$ECOND-CUSTOM_STRING WITH SPACES AND @*! CHARACTERS" exit 1 if not exist "%PREFIX%\pre_install_sentinel.txt" exit 1 diff --git a/examples/scripts/post_install.sh b/examples/scripts/post_install.sh index 54d2b268e..1db67d136 100644 --- a/examples/scripts/post_install.sh +++ b/examples/scripts/post_install.sh @@ -9,10 +9,17 @@ echo "INSTALLER_NAME=${INSTALLER_NAME}" echo "INSTALLER_VER=${INSTALLER_VER}" echo "INSTALLER_PLAT=${INSTALLER_PLAT}" echo "INSTALLER_TYPE=${INSTALLER_TYPE}" +echo "CUSTOM_VARIABLE_1=${CUSTOM_VARIABLE_1}" +echo "CUSTOM_VARIABLE_2=${CUSTOM_VARIABLE_2}" echo "PREFIX=${PREFIX}" test "${INSTALLER_NAME}" = "Scripts" test "${INSTALLER_VER}" = "X" +# shellcheck disable=SC2016 # String interpolation disabling is deliberate +test "${CUSTOM_VARIABLE_1}" = 'FIR$T-CUSTOM_'\''STRING'\'' WITH SPACES AND @*! "CHARACTERS"' +# shellcheck disable=SC2016 # String interpolation disabling is deliberate +test "${CUSTOM_VARIABLE_2}" = '$ECOND-CUSTOM_'\''STRING'\'' WITH SPACES AND @*! "CHARACTERS"' + if [[ $(uname -s) == Linux ]]; then if [[ ${INSTALLER_PLAT} != linux-* ]]; then exit 1 diff --git a/examples/scripts/pre_install.bat b/examples/scripts/pre_install.bat index d1bd0598a..5ece67c31 100644 --- a/examples/scripts/pre_install.bat +++ b/examples/scripts/pre_install.bat @@ -3,4 +3,6 @@ if not "%INSTALLER_VER%" == "X" exit 1 if not "%INSTALLER_PLAT%" == "win-64" exit 1 if not "%INSTALLER_TYPE%" == "EXE" exit 1 if "%PREFIX%" == "" exit 1 +if not "%CUSTOM_VARIABLE_1%" == "FIR$T-CUSTOM_STRING WITH SPACES AND @*! CHARACTERS" exit 1 +if not "%CUSTOM_VARIABLE_2%" == "$ECOND-CUSTOM_STRING WITH SPACES AND @*! CHARACTERS" exit 1 echo Added by pre-install script > "%PREFIX%\pre_install_sentinel.txt" diff --git a/examples/scripts/pre_install.sh b/examples/scripts/pre_install.sh index a865dcc0e..df0806980 100644 --- a/examples/scripts/pre_install.sh +++ b/examples/scripts/pre_install.sh @@ -6,10 +6,17 @@ echo "INSTALLER_NAME=${INSTALLER_NAME}" echo "INSTALLER_VER=${INSTALLER_VER}" echo "INSTALLER_PLAT=${INSTALLER_PLAT}" echo "INSTALLER_TYPE=${INSTALLER_TYPE}" +echo "CUSTOM_VARIABLE_1=${CUSTOM_VARIABLE_1}" +echo "CUSTOM_VARIABLE_2=${CUSTOM_VARIABLE_2}" echo "PREFIX=${PREFIX}" test "${INSTALLER_NAME}" = "Scripts" test "${INSTALLER_VER}" = "X" +# shellcheck disable=SC2016 # String interpolation disabling is deliberate +test "${CUSTOM_VARIABLE_1}" = 'FIR$T-CUSTOM_'\''STRING'\'' WITH SPACES AND @*! "CHARACTERS"' +# shellcheck disable=SC2016 # String interpolation disabling is deliberate +test "${CUSTOM_VARIABLE_2}" = '$ECOND-CUSTOM_'\''STRING'\'' WITH SPACES AND @*! "CHARACTERS"' + if [[ $(uname -s) == Linux ]]; then if [[ ${INSTALLER_PLAT} != linux-* ]]; then exit 1 diff --git a/news/718-script_env_variables-option b/news/718-script_env_variables-option new file mode 100644 index 000000000..9ff8e5f67 --- /dev/null +++ b/news/718-script_env_variables-option @@ -0,0 +1,21 @@ +### Enhancements + +* Added support for `script_env_variables` allowing specification of + environment variables in the `construct.yaml` for use by pre- and + post-install scripts. + +### Bug fixes + +* + +### Deprecations + +* + +### Docs + +* + +### Other + +*