From fd509018492b3ac5e34abbbb3787e4a90d32e8e2 Mon Sep 17 00:00:00 2001 From: ebert1 Date: Fri, 29 Oct 2021 12:48:06 +0200 Subject: [PATCH 01/11] Clean up whitespace --- activate.sh | 4 ---- config.sh | 1 - create_kernel.sh | 4 ++-- readme.md | 6 +++--- setup.sh | 3 --- 5 files changed, 5 insertions(+), 13 deletions(-) diff --git a/activate.sh b/activate.sh index bde09a1..083cd15 100644 --- a/activate.sh +++ b/activate.sh @@ -10,7 +10,3 @@ source ${ABSOLUTE_PATH}/modules.sh export PYTHONPATH=`echo ${ENV_DIR}/lib/python*/site-packages`:${PYTHONPATH} source ${ENV_DIR}/bin/activate - - - - diff --git a/config.sh b/config.sh index 17d0bd7..ad45c76 100644 --- a/config.sh +++ b/config.sh @@ -8,4 +8,3 @@ ABSOLUTE_PATH=`realpath ${RELATIVE_PATH}` ### User Configuration export ENV_NAME=`basename $ABSOLUTE_PATH` # Default Name of the venv is the directory that contains this file export ENV_DIR=${ABSOLUTE_PATH}/venv # Default location of this VENV is "./venv" - diff --git a/create_kernel.sh b/create_kernel.sh index 3e79328..d31fcea 100755 --- a/create_kernel.sh +++ b/create_kernel.sh @@ -13,7 +13,7 @@ echo "Setting up the kernel script in the following dir: " ${KERNELFILE} echo '#!/bin/bash source '"${ABSOLUTE_PATH}"'/activate.sh - + exec python -m ipykernel $@' > ${KERNELFILE} chmod a+x ${KERNELFILE} @@ -21,7 +21,7 @@ chmod a+x ${KERNELFILE} mkdir -p ~/.local/share/jupyter/kernels/${ENV_NAME} echo '{ "argv": [ - "'"${KERNELFILE}"'", + "'"${KERNELFILE}"'", "-f", "{connection_file}" ], diff --git a/readme.md b/readme.md index 138ef29..efeee80 100644 --- a/readme.md +++ b/readme.md @@ -8,7 +8,7 @@ typical supercomputer setups, including creating Jupyter Kernels. On Supercomputers, typically a basic environment based on **Environment Modules**. This setup is carefully curated and optimized, including compilers, MPI version etc. Extra Python packages can be installed with pip into user space. This, however, does not create a reproducible environment that can be used -by other users as well. +by other users as well. Conceptuall, with Virtual Environments, it is easily possible to create project-based virtual environments. These scripts streamline the creation und usage of such environments and make it easy for a users to share a setup @@ -16,12 +16,12 @@ and to put it under version control with the main code. Furthermore, in typical compute setup of scientific projects, one or more packages possibly are in active developement. In the context of these setups, it is intended to include them as submodules and add integrate -them into the workflow. This can e.g. mean that a compilation step is added in the setup step and +them into the workflow. This can e.g. mean that a compilation step is added in the setup step and setting appropriate environment variables is included in the activation step. # Details The setup is configured in the bash script `config.sh`. The user can define a name for the venv and directory -where the venv files are stored. This defaults to the directory name of the containing folder and the "." folder +where the venv files are stored. This defaults to the directory name of the containing folder and the "." folder of the scripts. Please **edit** this file if you want a custom name and location for the venv. The modules ontop of which the the venv should be built are defined in `modules.sh`. Please **edit** the file diff --git a/setup.sh b/setup.sh index dc4ed98..0568cbb 100755 --- a/setup.sh +++ b/setup.sh @@ -10,6 +10,3 @@ python -m venv --prompt $ENV_NAME --system-site-packages ${ENV_DIR} source ${ABSOLUTE_PATH}/activate.sh pip install -r ${ABSOLUTE_PATH}/requirements.txt - - - -- GitLab From de71887fcf8b9532dbf2ef7a69d8693f1f760208 Mon Sep 17 00:00:00 2001 From: ebert1 Date: Fri, 29 Oct 2021 12:47:10 +0200 Subject: [PATCH 02/11] Fix typos --- readme.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/readme.md b/readme.md index efeee80..0d55f36 100644 --- a/readme.md +++ b/readme.md @@ -10,12 +10,12 @@ curated and optimized, including compilers, MPI version etc. Extra Python packag with pip into user space. This, however, does not create a reproducible environment that can be used by other users as well. -Conceptuall, with Virtual Environments, it is easily possible to create project-based virtual environments. -These scripts streamline the creation und usage of such environments and make it easy for a users to share a setup +Conceptually, with Virtual Environments, it is easily possible to create project-based virtual environments. +These scripts streamline the creation and usage of such environments and make it easy for a users to share a setup and to put it under version control with the main code. Furthermore, in typical compute setup of scientific projects, one or more packages possibly are in active -developement. In the context of these setups, it is intended to include them as submodules and add integrate +development. In the context of these setups, it is intended to include them as submodules and add integrate them into the workflow. This can e.g. mean that a compilation step is added in the setup step and setting appropriate environment variables is included in the activation step. @@ -24,7 +24,7 @@ The setup is configured in the bash script `config.sh`. The user can define a na where the venv files are stored. This defaults to the directory name of the containing folder and the "." folder of the scripts. Please **edit** this file if you want a custom name and location for the venv. -The modules ontop of which the the venv should be built are defined in `modules.sh`. Please **edit** the file +The modules on top of which the the venv should be built are defined in `modules.sh`. Please **edit** the file to your needs. The file `requirements.txt` contains a list of packages to be installed during the setup process. Add required @@ -35,13 +35,13 @@ file to add a setup step for submodules (e.g. compilation of libraries). If only can remain unchanged. The script `activate.sh` sets the environment variables such that the venv can be used. Please **edit** this file -to add environment variables for submodules. Note that it the script must be *sourced* to take effect. Example: +to add environment variables for submodules. Note that the script must be *sourced* to take effect. Example: ```bash source /activate.sh ``` The script `create_kernel.sh` will create a kernel json file in the user's home directory that can be found -by jupyter and a helper script in the virtual environment folder. +by Jupyter and a helper script in the virtual environment folder. @@ -50,4 +50,4 @@ by jupyter and a helper script in the virtual environment folder. 2. Edit `modules.sh` to change the modules loaded prior to the creation of the venv. 3. Edit `requirements.txt` to change the packages to be installed during setup. 4. Edit `setup.sh` and `activate.sh` to add extra steps for custom modules. -5. Create a kernel with `create_kernel.sh` +5. Create a kernel with `create_kernel.sh`. -- GitLab From 93647ff59b5a9221a9aa57d456704872be600f53 Mon Sep 17 00:00:00 2001 From: ebert1 Date: Fri, 29 Oct 2021 12:47:14 +0200 Subject: [PATCH 03/11] Mention that `setup.sh` needs to be ran --- readme.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 0d55f36..635ca9c 100644 --- a/readme.md +++ b/readme.md @@ -32,7 +32,7 @@ packages to this file to reproducibly add them to the venv. The script `setup.sh` creates the venv according to the config given in `config.sh`. Please **edit** this file to add a setup step for submodules (e.g. compilation of libraries). If only plain venvs are used, this file -can remain unchanged. +can remain unchanged. Note that the script *must* be ran at least once after the above configurations to actually create the environment. The script `activate.sh` sets the environment variables such that the venv can be used. Please **edit** this file to add environment variables for submodules. Note that the script must be *sourced* to take effect. Example: @@ -50,4 +50,5 @@ by Jupyter and a helper script in the virtual environment folder. 2. Edit `modules.sh` to change the modules loaded prior to the creation of the venv. 3. Edit `requirements.txt` to change the packages to be installed during setup. 4. Edit `setup.sh` and `activate.sh` to add extra steps for custom modules. -5. Create a kernel with `create_kernel.sh`. +5. Create the environment with `setup.sh`. +6. Create a kernel with `create_kernel.sh`. -- GitLab From 293c0254da8dca734ff989384ce9cb9470d84954 Mon Sep 17 00:00:00 2001 From: ebert1 Date: Fri, 29 Oct 2021 12:47:14 +0200 Subject: [PATCH 04/11] Explicitly indicate how scripts should be ran Could of course also use `./`, but then we may need to include `chmod u+x` as well. --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 635ca9c..0e11440 100644 --- a/readme.md +++ b/readme.md @@ -50,5 +50,5 @@ by Jupyter and a helper script in the virtual environment folder. 2. Edit `modules.sh` to change the modules loaded prior to the creation of the venv. 3. Edit `requirements.txt` to change the packages to be installed during setup. 4. Edit `setup.sh` and `activate.sh` to add extra steps for custom modules. -5. Create the environment with `setup.sh`. -6. Create a kernel with `create_kernel.sh`. +5. Create the environment with `bash setup.sh`. +6. Create a kernel with `bash create_kernel.sh`. -- GitLab From 4e6b2f6eef29e569a9da143908e6b80bc23fae53 Mon Sep 17 00:00:00 2001 From: ebert1 Date: Fri, 29 Oct 2021 12:47:15 +0200 Subject: [PATCH 05/11] Avoid interactive command This is simply clearer. --- modules.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules.sh b/modules.sh index d6d8a9d..e6c19f6 100644 --- a/modules.sh +++ b/modules.sh @@ -1 +1 @@ -ml GCC/9.3.0 ParaStationMPI/5.4.7-1 Python/3.8.5 +module load GCC/9.3.0 ParaStationMPI/5.4.7-1 Python/3.8.5 -- GitLab From b542c4dac959f5da5eead6f41d59c5a9ebb3b64c Mon Sep 17 00:00:00 2001 From: ebert1 Date: Fri, 29 Oct 2021 12:47:16 +0200 Subject: [PATCH 06/11] Purge modules before loading Better practice in order to separate the virtual environment cleanly from the one it is started from. --- modules.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/modules.sh b/modules.sh index e6c19f6..a3d9307 100644 --- a/modules.sh +++ b/modules.sh @@ -1 +1,2 @@ +module purge module load GCC/9.3.0 ParaStationMPI/5.4.7-1 Python/3.8.5 -- GitLab From 8059bc233a05e404a54b499b3bd037581f25780e Mon Sep 17 00:00:00 2001 From: ebert1 Date: Fri, 29 Oct 2021 12:47:16 +0200 Subject: [PATCH 07/11] Update module versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I picked the most recent versions that matched the newest stable GCC. ParaStationMPI does not yet have GCC 11 modules and not sure about stability of the GCC 11 module. --- modules.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules.sh b/modules.sh index a3d9307..6512ef5 100644 --- a/modules.sh +++ b/modules.sh @@ -1,2 +1,2 @@ module purge -module load GCC/9.3.0 ParaStationMPI/5.4.7-1 Python/3.8.5 +module load GCC/10.3.0 ParaStationMPI/5.4.10-1 Python/3.8.5 -- GitLab From 6ded5a5040e28cd5a7183fa3adc63cc89bc8e19d Mon Sep 17 00:00:00 2001 From: ebert1 Date: Fri, 29 Oct 2021 12:47:17 +0200 Subject: [PATCH 08/11] Use more portable `pip` invocation --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index 0568cbb..4ef6666 100755 --- a/setup.sh +++ b/setup.sh @@ -9,4 +9,4 @@ python -m venv --prompt $ENV_NAME --system-site-packages ${ENV_DIR} source ${ABSOLUTE_PATH}/activate.sh -pip install -r ${ABSOLUTE_PATH}/requirements.txt +python -m pip install -r ${ABSOLUTE_PATH}/requirements.txt -- GitLab From 8b389d1d84b1cea2cbfbac5b5a3a8749b636f483 Mon Sep 17 00:00:00 2001 From: ebert1 Date: Fri, 29 Oct 2021 12:47:17 +0200 Subject: [PATCH 09/11] Improve bash code - more modern bash code (e.g. replace backtick expansions with `$([...])`) - handle more paths (e.g. with spaces); this boils down to simply quoting every variable - prefer clearer `${BASH_SOURCE[0]}` over `$BASH_SOURCE` --- activate.sh | 15 ++++++++------- config.sh | 10 +++++----- create_kernel.sh | 24 ++++++++++++------------ setup.sh | 15 ++++++++------- 4 files changed, 33 insertions(+), 31 deletions(-) diff --git a/activate.sh b/activate.sh index 083cd15..174b748 100644 --- a/activate.sh +++ b/activate.sh @@ -1,12 +1,13 @@ #!/bin/bash -RELATIVE_PATH=`dirname ${BASH_SOURCE}` -ABSOLUTE_PATH=`realpath ${RELATIVE_PATH}` -[[ $0 != $BASH_SOURCE ]] && echo "The activation script must be sourced, otherwise the virtual environment will not work." || ( echo "Vars script must be sourced." && exit 1) ; +RELATIVE_PATH="$(dirname "${BASH_SOURCE[0]}")" +ABSOLUTE_PATH="$(realpath "${RELATIVE_PATH}")" -source ${ABSOLUTE_PATH}/config.sh -source ${ABSOLUTE_PATH}/modules.sh +[[ "$0" != "${BASH_SOURCE[0]}" ]] && echo "The activation script must be sourced, otherwise the virtual environment will not work." || ( echo "Vars script must be sourced." && exit 1) ; -export PYTHONPATH=`echo ${ENV_DIR}/lib/python*/site-packages`:${PYTHONPATH} +source "${ABSOLUTE_PATH}"/config.sh +source "${ABSOLUTE_PATH}"/modules.sh -source ${ENV_DIR}/bin/activate +export PYTHONPATH="$(echo "${ENV_DIR}"/lib/python*/site-packages):${PYTHONPATH}" + +source "${ENV_DIR}"/bin/activate diff --git a/config.sh b/config.sh index ad45c76..ddf20c7 100644 --- a/config.sh +++ b/config.sh @@ -1,10 +1,10 @@ ## Check if this script is sourced -[[ $0 != $BASH_SOURCE ]] && echo "Setting vars" || ( echo "Vars script must be sourced." && exit 1) ; +[[ "$0" != "${BASH_SOURCE[0]}" ]] && echo "Setting vars" || ( echo "Vars script must be sourced." && exit 1) ; ## Determine location of this file -RELATIVE_PATH=`dirname ${BASH_SOURCE}` -ABSOLUTE_PATH=`realpath ${RELATIVE_PATH}` +RELATIVE_PATH="$(dirname "${BASH_SOURCE[0]}")" +ABSOLUTE_PATH="$(realpath "${RELATIVE_PATH}")" #################################### ### User Configuration -export ENV_NAME=`basename $ABSOLUTE_PATH` # Default Name of the venv is the directory that contains this file -export ENV_DIR=${ABSOLUTE_PATH}/venv # Default location of this VENV is "./venv" +export ENV_NAME="$(basename "$ABSOLUTE_PATH")" # Default Name of the venv is the directory that contains this file +export ENV_DIR="${ABSOLUTE_PATH}"/venv # Default location of this VENV is "./venv" diff --git a/create_kernel.sh b/create_kernel.sh index d31fcea..edff7c3 100755 --- a/create_kernel.sh +++ b/create_kernel.sh @@ -1,30 +1,30 @@ #!/bin/bash -RELATIVE_PATH=`dirname ${BASH_SOURCE}` -ABSOLUTE_PATH=`realpath ${RELATIVE_PATH}` -source ${ABSOLUTE_PATH}/config.sh +RELATIVE_PATH="$(dirname "${BASH_SOURCE[0]}")" +ABSOLUTE_PATH="$(realpath "${RELATIVE_PATH}")" +source "${ABSOLUTE_PATH}"/config.sh -KERNELFILE=${ENV_DIR}/kernel.sh +KERNELFILE="${ENV_DIR}"/kernel.sh -echo the name is $ENV_NAME +echo the name is "$ENV_NAME" -echo "Setting up the kernel script in the following dir: " ${KERNELFILE} +echo "Setting up the kernel script in the following dir: " "${KERNELFILE}" echo '#!/bin/bash -source '"${ABSOLUTE_PATH}"'/activate.sh +source "'"${ABSOLUTE_PATH}"'"/activate.sh -exec python -m ipykernel $@' > ${KERNELFILE} +exec python -m ipykernel "$@"' > "${KERNELFILE}" -chmod a+x ${KERNELFILE} +chmod a+x "${KERNELFILE}" -mkdir -p ~/.local/share/jupyter/kernels/${ENV_NAME} +mkdir -p ~/.local/share/jupyter/kernels/"${ENV_NAME}" echo '{ "argv": [ "'"${KERNELFILE}"'", "-f", "{connection_file}" ], - "display_name": "'${ENV_NAME}'", + "display_name": "'"${ENV_NAME}"'", "language": "python" -}' > ~/.local/share/jupyter/kernels/${ENV_NAME}/kernel.json +}' > ~/.local/share/jupyter/kernels/"${ENV_NAME}"/kernel.json diff --git a/setup.sh b/setup.sh index 4ef6666..8ef0bf6 100755 --- a/setup.sh +++ b/setup.sh @@ -1,12 +1,13 @@ #!/bin/bash -RELATIVE_PATH=`dirname ${BASH_SOURCE}` -ABSOLUTE_PATH=`realpath ${RELATIVE_PATH}` -source ${ABSOLUTE_PATH}/config.sh -source ${ABSOLUTE_PATH}/modules.sh +RELATIVE_PATH="$(dirname "${BASH_SOURCE[0]}")" +ABSOLUTE_PATH="$(realpath "${RELATIVE_PATH}")" -python -m venv --prompt $ENV_NAME --system-site-packages ${ENV_DIR} +source "${ABSOLUTE_PATH}"/config.sh +source "${ABSOLUTE_PATH}"/modules.sh -source ${ABSOLUTE_PATH}/activate.sh +python -m venv --prompt "$ENV_NAME" --system-site-packages "${ENV_DIR}" -python -m pip install -r ${ABSOLUTE_PATH}/requirements.txt +source "${ABSOLUTE_PATH}"/activate.sh + +python -m pip install -r "${ABSOLUTE_PATH}"/requirements.txt -- GitLab From da3a2b3f15996a4cc04866105028e7e5e9a9a817 Mon Sep 17 00:00:00 2001 From: ebert1 Date: Fri, 29 Oct 2021 12:47:18 +0200 Subject: [PATCH 10/11] Refactor `BASH_SOURCE` usage We now assign once at the top; this makes portability changes with regard to this variable easier. --- activate.sh | 6 ++++-- config.sh | 6 ++++-- create_kernel.sh | 4 +++- setup.sh | 4 +++- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/activate.sh b/activate.sh index 174b748..dd6e78e 100644 --- a/activate.sh +++ b/activate.sh @@ -1,9 +1,11 @@ #!/bin/bash -RELATIVE_PATH="$(dirname "${BASH_SOURCE[0]}")" +SOURCE_PATH="${BASH_SOURCE[0]}" + +RELATIVE_PATH="$(dirname "$SOURCE_PATH")" ABSOLUTE_PATH="$(realpath "${RELATIVE_PATH}")" -[[ "$0" != "${BASH_SOURCE[0]}" ]] && echo "The activation script must be sourced, otherwise the virtual environment will not work." || ( echo "Vars script must be sourced." && exit 1) ; +[[ "$0" != "${SOURCE_PATH}" ]] && echo "The activation script must be sourced, otherwise the virtual environment will not work." || ( echo "Vars script must be sourced." && exit 1) ; source "${ABSOLUTE_PATH}"/config.sh source "${ABSOLUTE_PATH}"/modules.sh diff --git a/config.sh b/config.sh index ddf20c7..8706f74 100644 --- a/config.sh +++ b/config.sh @@ -1,7 +1,9 @@ +SOURCE_PATH="${BASH_SOURCE[0]}" + ## Check if this script is sourced -[[ "$0" != "${BASH_SOURCE[0]}" ]] && echo "Setting vars" || ( echo "Vars script must be sourced." && exit 1) ; +[[ "$0" != "${SOURCE_PATH}" ]] && echo "Setting vars" || ( echo "Vars script must be sourced." && exit 1) ; ## Determine location of this file -RELATIVE_PATH="$(dirname "${BASH_SOURCE[0]}")" +RELATIVE_PATH="$(dirname "$SOURCE_PATH")" ABSOLUTE_PATH="$(realpath "${RELATIVE_PATH}")" #################################### diff --git a/create_kernel.sh b/create_kernel.sh index edff7c3..93dd606 100755 --- a/create_kernel.sh +++ b/create_kernel.sh @@ -1,6 +1,8 @@ #!/bin/bash -RELATIVE_PATH="$(dirname "${BASH_SOURCE[0]}")" +SOURCE_PATH="${BASH_SOURCE[0]}" + +RELATIVE_PATH="$(dirname "$SOURCE_PATH")" ABSOLUTE_PATH="$(realpath "${RELATIVE_PATH}")" source "${ABSOLUTE_PATH}"/config.sh diff --git a/setup.sh b/setup.sh index 8ef0bf6..491a50c 100755 --- a/setup.sh +++ b/setup.sh @@ -1,6 +1,8 @@ #!/bin/bash -RELATIVE_PATH="$(dirname "${BASH_SOURCE[0]}")" +SOURCE_PATH="${BASH_SOURCE[0]}" + +RELATIVE_PATH="$(dirname "$SOURCE_PATH")" ABSOLUTE_PATH="$(realpath "${RELATIVE_PATH}")" source "${ABSOLUTE_PATH}"/config.sh -- GitLab From 52fbeb24e7dd50b0ff430f524056e6579f7802bc Mon Sep 17 00:00:00 2001 From: ebert1 Date: Fri, 29 Oct 2021 12:47:19 +0200 Subject: [PATCH 11/11] Support ZSH ZSH does not set `BASH_SOURCE`, so we use a command to get the corresponding path. See also https://stackoverflow.com/a/28336473. --- activate.sh | 3 ++- config.sh | 2 +- create_kernel.sh | 2 +- setup.sh | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/activate.sh b/activate.sh index dd6e78e..1ebb7bc 100644 --- a/activate.sh +++ b/activate.sh @@ -1,6 +1,7 @@ #!/bin/bash -SOURCE_PATH="${BASH_SOURCE[0]}" +# See https://stackoverflow.com/a/28336473 +SOURCE_PATH="${BASH_SOURCE[0]:-${(%):-%x}}" RELATIVE_PATH="$(dirname "$SOURCE_PATH")" ABSOLUTE_PATH="$(realpath "${RELATIVE_PATH}")" diff --git a/config.sh b/config.sh index 8706f74..b7de5f7 100644 --- a/config.sh +++ b/config.sh @@ -1,4 +1,4 @@ -SOURCE_PATH="${BASH_SOURCE[0]}" +SOURCE_PATH="${BASH_SOURCE[0]:-${(%):-%x}}" ## Check if this script is sourced [[ "$0" != "${SOURCE_PATH}" ]] && echo "Setting vars" || ( echo "Vars script must be sourced." && exit 1) ; diff --git a/create_kernel.sh b/create_kernel.sh index 93dd606..e09007b 100755 --- a/create_kernel.sh +++ b/create_kernel.sh @@ -1,6 +1,6 @@ #!/bin/bash -SOURCE_PATH="${BASH_SOURCE[0]}" +SOURCE_PATH="${BASH_SOURCE[0]:-${(%):-%x}}" RELATIVE_PATH="$(dirname "$SOURCE_PATH")" ABSOLUTE_PATH="$(realpath "${RELATIVE_PATH}")" diff --git a/setup.sh b/setup.sh index 491a50c..326a7c4 100755 --- a/setup.sh +++ b/setup.sh @@ -1,6 +1,6 @@ #!/bin/bash -SOURCE_PATH="${BASH_SOURCE[0]}" +SOURCE_PATH="${BASH_SOURCE[0]:-${(%):-%x}}" RELATIVE_PATH="$(dirname "$SOURCE_PATH")" ABSOLUTE_PATH="$(realpath "${RELATIVE_PATH}")" -- GitLab