From f6173ad9fed08d1e9425ccd42ab2cfb69e9456b9 Mon Sep 17 00:00:00 2001 From: Lars Erik Wik Date: Thu, 19 Jun 2025 11:00:59 +0200 Subject: [PATCH 1/9] bootstrap-tarballs: Document code for fetching PR info Ticket: ENT-12600 Signed-off-by: Lars Erik Wik --- build-scripts/bootstrap-tarballs | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/build-scripts/bootstrap-tarballs b/build-scripts/bootstrap-tarballs index f9ba45f91..1c81b9921 100755 --- a/build-scripts/bootstrap-tarballs +++ b/build-scripts/bootstrap-tarballs @@ -14,18 +14,39 @@ mkdir -p $BASEDIR/output/tarballs # the first part of the script is not really critical set +e -# Get information about PRs among the used revisions. -# These PRs will have to be notified of build progress. +# Get information about PRs among the used revisions. These PRs will have to be +# notified of build progress. +# +# Variables such as MISSION_PORTAL_REV may be set by the CI (Jenkins) to build +# and test multiple PR's together. The variables typically hold a branch name +# or a pull request ID. PR IDs are preceded by 'pull' or 'origin/pull'. E.g.: +# - MISSION_PORTAL_REV=pull/1755 +# - MISSION_PORTAL_REV=origin/pull/1755 +# where the trailing number is the pull request ID. +# +# This loop fetches information about the PRs if the respective variable is set. +# for repo_spec in cfengine/buildscripts cfengine/core cfengine/masterfiles cfengine/enterprise cfengine/nova cfengine/mission-portal NorthernTechHQ/libntech; do # remove organization/ from start of repo_spec + # E.g. 'cfengine/mission-portal' -> 'mission-portal' repo="${repo_spec#*/}" + + # Convert to uppercase, swap hyphens with underscore and append '_REV' + # E.g. 'mission-portal' -> 'MISSION_PORTAL_REV' rev_param_name="$(echo $repo | tr '[:lower:]-' '[:upper:]_')_REV" + + # Try to dereference the result from above and skip the rest of the loop + # unless the variable is defined. revision="$(echo ${!rev_param_name})" || continue # dereference # remove "origin/" (if any) revision="${revision##origin/}" + + # Check to see if the resolved variable starts with 'pull/' if expr "$revision" : "pull/" >/dev/null; then + # Extract the revision number. E.g. 'pull/1755' -> '1755' pr_nr="$(echo $revision | cut -d/ -f2)" + get-github-pull-request-info "$repo_spec" "$pr_nr" >> $BASEDIR/output/PRs fi done @@ -103,4 +124,3 @@ if test -f "$BASEDIR/mission-portal/ldap/composer.json"; then php /usr/bin/composer.phar install --no-dev fi ) - From 9536d566b33251fc9914d734eef1f8fbb9d12c2e Mon Sep 17 00:00:00 2001 From: Lars Erik Wik Date: Thu, 19 Jun 2025 13:01:14 +0200 Subject: [PATCH 2/9] bootstrap-tarballs: Document code that builds tarballs Ticket: ENT-12600 Signed-off-by: Lars Erik Wik --- build-scripts/bootstrap-tarballs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/build-scripts/bootstrap-tarballs b/build-scripts/bootstrap-tarballs index 1c81b9921..14d8f7058 100755 --- a/build-scripts/bootstrap-tarballs +++ b/build-scripts/bootstrap-tarballs @@ -54,6 +54,7 @@ done # now script failures should fail the script set -e +# Build tarball from core repository cd $BASEDIR/core rm cfengine-3.*.tar.gz || true git rev-parse HEAD > $BASEDIR/output/core-commitID @@ -63,13 +64,15 @@ make dist mv cfengine-3.*.tar.gz $BASEDIR/output/tarballs/ make distclean +# Build tarballs from masterfiles repository cd $BASEDIR/masterfiles rm cfengine-masterfiles*.tar.gz || true git rev-parse HEAD > $BASEDIR/output/masterfiles-commitID # Configure in order to run "make dist", deleted later. ./configure -make dist # source tarball -make tar-package # package tarball +make dist # source tarball +make tar-package # package tarball (containing all files as if they were + # installed under "prefix".) mv cfengine-masterfiles*.tar.gz $BASEDIR/output/tarballs/ make distclean From c574435ddd552d5fc17586daa7df7ef4bb9cd413 Mon Sep 17 00:00:00 2001 From: Lars Erik Wik Date: Thu, 19 Jun 2025 13:02:41 +0200 Subject: [PATCH 3/9] bootstrap-tarballs: Document code that computes checksum list Ticket: ENT-12600 Signed-off-by: Lars Erik Wik --- build-scripts/bootstrap-tarballs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build-scripts/bootstrap-tarballs b/build-scripts/bootstrap-tarballs index 14d8f7058..30736746b 100755 --- a/build-scripts/bootstrap-tarballs +++ b/build-scripts/bootstrap-tarballs @@ -76,8 +76,12 @@ make tar-package # package tarball (containing all files as if they were mv cfengine-masterfiles*.tar.gz $BASEDIR/output/tarballs/ make distclean +# Compute a checksum list that can be used to verify the integrity of the +# tarballs cd $BASEDIR/output/tarballs sha256sum *.tar.gz > sha256sums.txt +# Add the BSD (16-bit) checksum of the checksum list to it's filename. This way +# you can verify the integrity of the checksum list itself. CKSUM=`sum sha256sums.txt | cut -d ' ' -f 1` mv sha256sums.txt sha256sums.$CKSUM.txt From 629352ca48dad1ea66903fa497169d47fd9f523a Mon Sep 17 00:00:00 2001 From: Lars Erik Wik Date: Thu, 19 Jun 2025 13:03:26 +0200 Subject: [PATCH 4/9] bootstrap-tarballs: Document code that installs dependencies I feel like the installation of dependencies does not belong here. Maybe they should go in to the install-dependencies script? Ticket: ENT-12600 Signed-off-by: Lars Erik Wik --- build-scripts/bootstrap-tarballs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build-scripts/bootstrap-tarballs b/build-scripts/bootstrap-tarballs index 30736746b..6bd4a32db 100755 --- a/build-scripts/bootstrap-tarballs +++ b/build-scripts/bootstrap-tarballs @@ -85,6 +85,7 @@ sha256sum *.tar.gz > sha256sums.txt CKSUM=`sum sha256sums.txt | cut -d ' ' -f 1` mv sha256sums.txt sha256sums.$CKSUM.txt +# Install javascript dependencies ( if test -f "$BASEDIR/mission-portal/public/scripts/package.json"; then cd $BASEDIR/mission-portal/public/scripts @@ -101,6 +102,7 @@ if test -f "$BASEDIR/mission-portal/public/scripts/package.json"; then fi ) +# Install PHP dependencies from the mission-portal repository ( if test -f "$BASEDIR/mission-portal/composer.json"; then cd $BASEDIR/mission-portal @@ -109,6 +111,7 @@ if test -f "$BASEDIR/mission-portal/composer.json"; then fi ) +# Install PHP dependencies from the nova repository ( if test -f "$BASEDIR/nova/api/http/composer.json"; then cd $BASEDIR/nova/api/http @@ -117,6 +120,7 @@ if test -f "$BASEDIR/nova/api/http/composer.json"; then fi ) +# Compile Mission Portal styles ( if test -f "$BASEDIR/mission-portal/public/themes/default/bootstrap/cfengine_theme.less"; then cd $BASEDIR/mission-portal/public/themes/default/bootstrap @@ -124,6 +128,7 @@ if test -f "$BASEDIR/mission-portal/public/themes/default/bootstrap/cfengine_the fi ) +# Install LDAP API dependencies ( if test -f "$BASEDIR/mission-portal/ldap/composer.json"; then cd $BASEDIR/mission-portal/ldap From a4cf8822007dbe203f0ca7251ec2d915ee8fc278 Mon Sep 17 00:00:00 2001 From: Lars Erik Wik Date: Thu, 19 Jun 2025 13:30:36 +0200 Subject: [PATCH 5/9] bootstrap-tarballs: Fixed shellcheck issues Signed-off-by: Lars Erik Wik --- build-scripts/bootstrap-tarballs | 58 ++++++++++++++++---------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/build-scripts/bootstrap-tarballs b/build-scripts/bootstrap-tarballs index 6bd4a32db..9afb3b927 100755 --- a/build-scripts/bootstrap-tarballs +++ b/build-scripts/bootstrap-tarballs @@ -4,12 +4,12 @@ _dir=$(readlink -e "$(dirname "$0")") # refactored a few functions into single file scripts for easier development/debugging, see ENT-12741 and ENT-12595 # Easier to add a path to a script than source a file of functions. export PATH="$_dir"/bin:$PATH -. `dirname "$0"`/functions +. "$(dirname "$0")"/functions . detect-environment . compile-options . version -mkdir -p $BASEDIR/output/tarballs +mkdir -p "$BASEDIR"/output/tarballs # the first part of the script is not really critical set +e @@ -33,11 +33,11 @@ for repo_spec in cfengine/buildscripts cfengine/core cfengine/masterfiles cfengi # Convert to uppercase, swap hyphens with underscore and append '_REV' # E.g. 'mission-portal' -> 'MISSION_PORTAL_REV' - rev_param_name="$(echo $repo | tr '[:lower:]-' '[:upper:]_')_REV" + rev_param_name="$(echo "$repo" | tr '[:lower:]-' '[:upper:]_')_REV" # Try to dereference the result from above and skip the rest of the loop # unless the variable is defined. - revision="$(echo ${!rev_param_name})" || continue # dereference + revision="${!rev_param_name}" || continue # remove "origin/" (if any) revision="${revision##origin/}" @@ -45,9 +45,9 @@ for repo_spec in cfengine/buildscripts cfengine/core cfengine/masterfiles cfengi # Check to see if the resolved variable starts with 'pull/' if expr "$revision" : "pull/" >/dev/null; then # Extract the revision number. E.g. 'pull/1755' -> '1755' - pr_nr="$(echo $revision | cut -d/ -f2)" + pr_nr="$(echo "$revision" | cut -d/ -f2)" - get-github-pull-request-info "$repo_spec" "$pr_nr" >> $BASEDIR/output/PRs + get-github-pull-request-info "$repo_spec" "$pr_nr" >> "$BASEDIR"/output/PRs fi done @@ -55,57 +55,57 @@ done set -e # Build tarball from core repository -cd $BASEDIR/core +cd "$BASEDIR"/core rm cfengine-3.*.tar.gz || true -git rev-parse HEAD > $BASEDIR/output/core-commitID +git rev-parse HEAD > "$BASEDIR"/output/core-commitID # Configure in order to run "make dist", deleted later. ./configure -C make dist -mv cfengine-3.*.tar.gz $BASEDIR/output/tarballs/ +mv cfengine-3.*.tar.gz "$BASEDIR"/output/tarballs/ make distclean # Build tarballs from masterfiles repository -cd $BASEDIR/masterfiles +cd "$BASEDIR"/masterfiles rm cfengine-masterfiles*.tar.gz || true -git rev-parse HEAD > $BASEDIR/output/masterfiles-commitID +git rev-parse HEAD > "$BASEDIR"/output/masterfiles-commitID # Configure in order to run "make dist", deleted later. ./configure make dist # source tarball make tar-package # package tarball (containing all files as if they were # installed under "prefix".) -mv cfengine-masterfiles*.tar.gz $BASEDIR/output/tarballs/ +mv cfengine-masterfiles*.tar.gz "$BASEDIR"/output/tarballs/ make distclean # Compute a checksum list that can be used to verify the integrity of the # tarballs -cd $BASEDIR/output/tarballs -sha256sum *.tar.gz > sha256sums.txt +cd "$BASEDIR"/output/tarballs +sha256sum -- *.tar.gz > sha256sums.txt # Add the BSD (16-bit) checksum of the checksum list to it's filename. This way # you can verify the integrity of the checksum list itself. -CKSUM=`sum sha256sums.txt | cut -d ' ' -f 1` -mv sha256sums.txt sha256sums.$CKSUM.txt +CKSUM=$(sum sha256sums.txt | cut -d ' ' -f 1) +mv sha256sums.txt sha256sums."$CKSUM".txt # Install javascript dependencies ( -if test -f "$BASEDIR/mission-portal/public/scripts/package.json"; then - cd $BASEDIR/mission-portal/public/scripts +if test -f "$BASEDIR"/mission-portal/public/scripts/package.json; then + cd "$BASEDIR"/mission-portal/public/scripts # display node & npm versions npm --version node --version # install dependencies from npmjs - npm ci --prefix $BASEDIR/mission-portal/public/scripts/ + npm ci --prefix "$BASEDIR"/mission-portal/public/scripts/ # build react components - npm run build --prefix $BASEDIR/mission-portal/public/scripts/ + npm run build --prefix "$BASEDIR"/mission-portal/public/scripts/ # remove the packages specified in devDependencies - npm prune --omit=dev --prefix $BASEDIR/mission-portal/public/scripts/ + npm prune --omit=dev --prefix "$BASEDIR"/mission-portal/public/scripts/ fi ) # Install PHP dependencies from the mission-portal repository ( -if test -f "$BASEDIR/mission-portal/composer.json"; then - cd $BASEDIR/mission-portal +if test -f "$BASEDIR"/mission-portal/composer.json; then + cd "$BASEDIR"/mission-portal # install PHP dependencies from composer php /usr/bin/composer.phar install --no-dev fi @@ -113,8 +113,8 @@ fi # Install PHP dependencies from the nova repository ( -if test -f "$BASEDIR/nova/api/http/composer.json"; then - cd $BASEDIR/nova/api/http +if test -f "$BASEDIR"/nova/api/http/composer.json; then + cd "$BASEDIR"/nova/api/http # install PHP dependencies from composer php /usr/bin/composer.phar install --no-dev --ignore-platform-reqs fi @@ -122,16 +122,16 @@ fi # Compile Mission Portal styles ( -if test -f "$BASEDIR/mission-portal/public/themes/default/bootstrap/cfengine_theme.less"; then - cd $BASEDIR/mission-portal/public/themes/default/bootstrap +if test -f "$BASEDIR"/mission-portal/public/themes/default/bootstrap/cfengine_theme.less; then + cd "$BASEDIR"/mission-portal/public/themes/default/bootstrap npx -p less lessc --compress ./cfengine_theme.less ./compiled/css/cfengine.less.css fi ) # Install LDAP API dependencies ( -if test -f "$BASEDIR/mission-portal/ldap/composer.json"; then - cd $BASEDIR/mission-portal/ldap +if test -f "$BASEDIR"/mission-portal/ldap/composer.json; then + cd "$BASEDIR"/mission-portal/ldap # install PHP dependencies from composer php /usr/bin/composer.phar install --no-dev fi From be0f5c090c9326722b97b50a54d839527f2a4386 Mon Sep 17 00:00:00 2001 From: Lars Erik Wik Date: Thu, 19 Jun 2025 13:38:00 +0200 Subject: [PATCH 6/9] bootstrap-tarballs: Remove extra newline for consistency Signed-off-by: Lars Erik Wik --- build-scripts/bootstrap-tarballs | 1 - 1 file changed, 1 deletion(-) diff --git a/build-scripts/bootstrap-tarballs b/build-scripts/bootstrap-tarballs index 9afb3b927..381bd80ec 100755 --- a/build-scripts/bootstrap-tarballs +++ b/build-scripts/bootstrap-tarballs @@ -98,7 +98,6 @@ if test -f "$BASEDIR"/mission-portal/public/scripts/package.json; then npm run build --prefix "$BASEDIR"/mission-portal/public/scripts/ # remove the packages specified in devDependencies npm prune --omit=dev --prefix "$BASEDIR"/mission-portal/public/scripts/ - fi ) From 287b447b3daa61554528852fd0eeef39d72c8c5d Mon Sep 17 00:00:00 2001 From: Lars Erik Wik Date: Thu, 19 Jun 2025 13:47:56 +0200 Subject: [PATCH 7/9] bootstrap-tarballs: Use rm -f instead of || true The use of `|| true` will cause an error message to be printed by `rm` which may lead QA personnel to believe that there is something wrong while there is not. -f will simply ignore nonexistent files. ``` rm: cannot remove 'nosuchfile': No such file or directory ``` Signed-off-by: Lars Erik Wik --- build-scripts/bootstrap-tarballs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-scripts/bootstrap-tarballs b/build-scripts/bootstrap-tarballs index 381bd80ec..ce7e7d469 100755 --- a/build-scripts/bootstrap-tarballs +++ b/build-scripts/bootstrap-tarballs @@ -56,7 +56,7 @@ set -e # Build tarball from core repository cd "$BASEDIR"/core -rm cfengine-3.*.tar.gz || true +rm -f cfengine-3.*.tar.gz git rev-parse HEAD > "$BASEDIR"/output/core-commitID # Configure in order to run "make dist", deleted later. ./configure -C @@ -66,7 +66,7 @@ make distclean # Build tarballs from masterfiles repository cd "$BASEDIR"/masterfiles -rm cfengine-masterfiles*.tar.gz || true +rm -f cfengine-masterfiles*.tar.gz git rev-parse HEAD > "$BASEDIR"/output/masterfiles-commitID # Configure in order to run "make dist", deleted later. ./configure From 83a03294d4eb21222cdf4eb98cd394ae419dcf19 Mon Sep 17 00:00:00 2001 From: Lars Erik Wik Date: Thu, 19 Jun 2025 15:14:52 +0200 Subject: [PATCH 8/9] bootstrap-tarballs: decreased verboseness Signed-off-by: Lars Erik Wik --- build-scripts/bootstrap-tarballs | 50 ++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/build-scripts/bootstrap-tarballs b/build-scripts/bootstrap-tarballs index ce7e7d469..255a20e77 100755 --- a/build-scripts/bootstrap-tarballs +++ b/build-scripts/bootstrap-tarballs @@ -1,4 +1,4 @@ -#!/bin/bash -x +#!/bin/bash _dir=$(readlink -e "$(dirname "$0")") # refactored a few functions into single file scripts for easier development/debugging, see ENT-12741 and ENT-12595 @@ -59,22 +59,30 @@ cd "$BASEDIR"/core rm -f cfengine-3.*.tar.gz git rev-parse HEAD > "$BASEDIR"/output/core-commitID # Configure in order to run "make dist", deleted later. -./configure -C -make dist +echo "$(basename "$0"): Debug: Running configure on core repository..." +run_and_print_on_failure ./configure -C +echo "$(basename "$0"): Debug: Running make dist on core repository..." +run_and_print_on_failure make dist mv cfengine-3.*.tar.gz "$BASEDIR"/output/tarballs/ -make distclean +echo "$(basename "$0"): Debug: Running make distclean on core repository..." +run_and_print_on_failure make distclean # Build tarballs from masterfiles repository cd "$BASEDIR"/masterfiles rm -f cfengine-masterfiles*.tar.gz git rev-parse HEAD > "$BASEDIR"/output/masterfiles-commitID # Configure in order to run "make dist", deleted later. -./configure -make dist # source tarball -make tar-package # package tarball (containing all files as if they were - # installed under "prefix".) +echo "$(basename "$0"): Debug: Running configure on masterfiles repository..." +run_and_print_on_failure ./configure +echo "$(basename "$0"): Debug: Running make dist on masterfiles repository..." +run_and_print_on_failure make dist # source tarball +echo "$(basename "$0"): Debug: Running make tar-package on masterfiles repository..." +run_and_print_on_failure make tar-package # package tarball (containing all + # files as if they were installed + # under "prefix".) mv cfengine-masterfiles*.tar.gz "$BASEDIR"/output/tarballs/ -make distclean +echo "$(basename "$0"): Debug: Running make distclean on masterfiles repository..." +run_and_print_on_failure make distclean # Compute a checksum list that can be used to verify the integrity of the # tarballs @@ -85,7 +93,7 @@ sha256sum -- *.tar.gz > sha256sums.txt CKSUM=$(sum sha256sums.txt | cut -d ' ' -f 1) mv sha256sums.txt sha256sums."$CKSUM".txt -# Install javascript dependencies +echo "$(basename "$0"): Debug: Installing javascript dependencies..." ( if test -f "$BASEDIR"/mission-portal/public/scripts/package.json; then cd "$BASEDIR"/mission-portal/public/scripts @@ -93,45 +101,45 @@ if test -f "$BASEDIR"/mission-portal/public/scripts/package.json; then npm --version node --version # install dependencies from npmjs - npm ci --prefix "$BASEDIR"/mission-portal/public/scripts/ + run_and_print_on_failure npm ci --prefix "$BASEDIR"/mission-portal/public/scripts/ # build react components - npm run build --prefix "$BASEDIR"/mission-portal/public/scripts/ + run_and_print_on_failure npm run build --prefix "$BASEDIR"/mission-portal/public/scripts/ # remove the packages specified in devDependencies - npm prune --omit=dev --prefix "$BASEDIR"/mission-portal/public/scripts/ + run_and_print_on_failure npm prune --omit=dev --prefix "$BASEDIR"/mission-portal/public/scripts/ fi ) -# Install PHP dependencies from the mission-portal repository +echo "$(basename "$0"): Debug: Installing PHP dependencies from mission-portal repository..." ( if test -f "$BASEDIR"/mission-portal/composer.json; then cd "$BASEDIR"/mission-portal # install PHP dependencies from composer - php /usr/bin/composer.phar install --no-dev + run_and_print_on_failure php /usr/bin/composer.phar install --no-dev fi ) -# Install PHP dependencies from the nova repository +echo "$(basename "$0"): Debug: Installing PHP dependencies from nova repository..." ( if test -f "$BASEDIR"/nova/api/http/composer.json; then cd "$BASEDIR"/nova/api/http # install PHP dependencies from composer - php /usr/bin/composer.phar install --no-dev --ignore-platform-reqs + run_and_print_on_failure php /usr/bin/composer.phar install --no-dev --ignore-platform-reqs fi ) -# Compile Mission Portal styles +echo "$(basename "$0"): Debug: Compiling Mission Portal styles..." ( if test -f "$BASEDIR"/mission-portal/public/themes/default/bootstrap/cfengine_theme.less; then cd "$BASEDIR"/mission-portal/public/themes/default/bootstrap - npx -p less lessc --compress ./cfengine_theme.less ./compiled/css/cfengine.less.css + run_and_print_on_failure npx -p less lessc --compress ./cfengine_theme.less ./compiled/css/cfengine.less.css fi ) -# Install LDAP API dependencies +echo "$(basename "$0"): Debug: Installing LDAP API dependencies..." ( if test -f "$BASEDIR"/mission-portal/ldap/composer.json; then cd "$BASEDIR"/mission-portal/ldap # install PHP dependencies from composer - php /usr/bin/composer.phar install --no-dev + run_and_print_on_failure php /usr/bin/composer.phar install --no-dev fi ) From 0bcf793ac27960361dcf61701749a41609f373f8 Mon Sep 17 00:00:00 2001 From: Lars Erik Wik Date: Fri, 20 Jun 2025 12:00:41 +0200 Subject: [PATCH 9/9] bootstrap-tarballs: comment explaining what it does Added a comment to the top of the file explaining what the script does and how you can run it. Ticket: ENT-12600 Signed-off-by: Lars Erik Wik --- build-scripts/bootstrap-tarballs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/build-scripts/bootstrap-tarballs b/build-scripts/bootstrap-tarballs index 255a20e77..bb24fd9bd 100755 --- a/build-scripts/bootstrap-tarballs +++ b/build-scripts/bootstrap-tarballs @@ -1,5 +1,29 @@ #!/bin/bash +# This script is supposed generate tarballs from the core & masterfiles +# repositories. We also use these tarballs later in the build process to make +# sure that they actually work. +# +# Currently this script also fetches pull request info and installs PHP and +# javascript dependencies. This core really does not belong here. Created a +# ticket move it (see ENT-13064). +# +# You will first need to run the autogen script. E.g.: +# PROJECT=community ./buildscripts/build-scripts/autogen +# Then you can run it like this: +# BUILD_TYPE=DEBUG ./buildscripts/build-scripts/bootstrap-tarballs +# +# The script expects the following repositories to be side by side: +# . +# ├── buildscripts +# ├── core +# ├── enterprise +# ├── nova +# ├── mission-portal +# ├── libntech +# └── masterfiles +# + _dir=$(readlink -e "$(dirname "$0")") # refactored a few functions into single file scripts for easier development/debugging, see ENT-12741 and ENT-12595 # Easier to add a path to a script than source a file of functions.