mirror of
https://github.com/ironfox-oss/IronFox.git
synced 2026-09-16 08:21:59 -04:00
Notably, this adds checks to ensure necessary executables and environment variables are available and set-up properly, adds new utilities files for certain functionality (to avoid redundancy/duplication) Signed-off-by: celenity <celenity@celenity.dev>
299 lines
9.5 KiB
Bash
Executable File
299 lines
9.5 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
set -euo pipefail
|
|
|
|
# File utility functions
|
|
|
|
# Set-up our environment
|
|
if [[ -z "${IRONFOX_SET_ENVS+x}" ]]; then
|
|
/bin/bash $(dirname $0)/env.sh || exit 1
|
|
fi
|
|
source $(dirname $0)/env.sh || exit 1
|
|
|
|
# Include utilities
|
|
source "${IRONFOX_UTILS}" || exit 1
|
|
|
|
# Produce a (reproducible) archive from a directory
|
|
## For reference/details on this process, see...
|
|
## https://codeberg.org/celenity/Phoenix/issues/314
|
|
## https://www.gnu.org/software/tar/manual/html_node/Reproducibility.html
|
|
## https://wiki.debian.org/ReproducibleBuilds/TimestampsInZip
|
|
## https://stackoverflow.com/questions/52668432/tar-package-has-different-checksum-for-exactly-the-same-content
|
|
function create_archive() {
|
|
function print_usage() {
|
|
echo "Usage: create_archive '/path/to/dir' '/path/to/output_archive'"
|
|
}
|
|
|
|
if [[ -z "${1+x}" ]]; then
|
|
echo_red_text 'ERROR: Please specify the path to a directory!'
|
|
print_usage
|
|
exit 1
|
|
fi
|
|
|
|
if [[ -z "${2+x}" ]]; then
|
|
echo_red_text 'ERROR: Please specify the path to the desired output archive!'
|
|
print_usage
|
|
exit 1
|
|
fi
|
|
|
|
# Ensure we have dirname
|
|
verify_exec "${IRONFOX_DIRNAME}" 'IRONFOX_DIRNAME' || exit 1
|
|
|
|
# Ensure we have dot_clean
|
|
if [[ "${IRONFOX_OS}" == 'osx' ]]; then
|
|
verify_exec "${IRONFOX_DOT_CLEAN}" 'IRONFOX_DOT_CLEAN' || exit 1
|
|
fi
|
|
|
|
# Ensure we have find
|
|
verify_exec "${IRONFOX_FIND}" 'IRONFOX_FIND' || exit 1
|
|
|
|
# Ensure we have GNU date
|
|
verify_exec "${IRONFOX_DATE}" 'IRONFOX_DATE' || exit 1
|
|
|
|
# Ensure we have head
|
|
verify_exec "${IRONFOX_HEAD}" 'IRONFOX_HEAD' || exit 1
|
|
|
|
# Ensure we have ls
|
|
verify_exec "${IRONFOX_LS}" 'IRONFOX_LS' || exit 1
|
|
|
|
# Ensure we have mkdir
|
|
verify_exec "${IRONFOX_MKDIR}" 'IRONFOX_MKDIR' || exit 1
|
|
|
|
# Ensure we have rm
|
|
verify_exec "${IRONFOX_RM}" 'IRONFOX_RM' || exit 1
|
|
|
|
# Ensure we have touch
|
|
verify_exec "${IRONFOX_TOUCH}" 'IRONFOX_TOUCH' || exit 1
|
|
|
|
# Ensure we have xargs
|
|
verify_exec "${IRONFOX_XARGS}" 'IRONFOX_XARGS' || exit 1
|
|
|
|
# Ensure we have `IRONFOX_VERSION_DATE`
|
|
if [[ -z "${IRONFOX_VERSION_DATE+x}" ]] || [[ "${IRONFOX_VERSION_DATE}" == "" ]]; then
|
|
echo_red_text "ERROR: 'IRONFOX_VERSION_DATE' is missing!"
|
|
exit 1
|
|
fi
|
|
|
|
local -r target_dir="$1"
|
|
local -r output_archive="$2"
|
|
|
|
# Determine the archive format
|
|
case "${output_archive}" in
|
|
*.zip)
|
|
# Ensure we have zip
|
|
verify_exec "${IRONFOX_ZIP}" 'IRONFOX_ZIP' || exit 1
|
|
|
|
local -r archive_format='zip'
|
|
;;
|
|
*.tar.xz)
|
|
# Ensure we have GNU tar
|
|
verify_exec "${IRONFOX_TAR}" 'IRONFOX_TAR' || exit 1
|
|
|
|
local -r archive_format='tar'
|
|
;;
|
|
*)
|
|
echo_red_text "ERROR: Unsupported archive format: '${output_archive}'!"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
if [[ ! -d "${target_dir}" ]]; then
|
|
echo_red_text "ERROR: Target directory ('${target_dir}') does not exist! Aborting..."
|
|
exit 1
|
|
fi
|
|
|
|
# Check if the output archive already exists
|
|
if [[ -f "${output_archive}" ]]; then
|
|
echo_red_text "'${output_archive}' already exists"
|
|
echo_red_text 'Continuing WILL override this archive'
|
|
read -p "Are you sure you want to proceed? [y/N] " -n 1 -r
|
|
echo
|
|
if [[ "${REPLY}" =~ ^[Yy]$ ]]; then
|
|
echo_red_text "Removing '${output_archive}'..."
|
|
"${IRONFOX_RM}" -f "${output_archive}"
|
|
else
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Set timezone to UTC for consistency
|
|
unset TZ
|
|
export TZ='UTC'
|
|
|
|
# If the directory for our output archive doesn't exist, create it
|
|
local -r output_archive_dir="$("${IRONFOX_DIRNAME}" "${output_archive}")"
|
|
if [[ ! -d "${output_archive_dir}" ]]; then
|
|
"${IRONFOX_MKDIR}" -p "${output_archive_dir}"
|
|
fi
|
|
|
|
# If we're on OS X, clean the target directory
|
|
if [[ "${IRONFOX_OS}" == 'osx' ]]; then
|
|
"${IRONFOX_DOT_CLEAN}" -mv "${target_dir}"
|
|
fi
|
|
|
|
# Set the file timestamp
|
|
## (This is derived from IRONFOX_VERSION_DATE at `versions.sh`)
|
|
local -r IRONFOX_STAMP="${IRONFOX_VERSION_DATE//./-}"
|
|
local -r IRONFOX_FIND_STAMP="$("${IRONFOX_DATE}" -d "${IRONFOX_STAMP}" +"%a, %d %b %Y %T %z")"
|
|
local -r IRONFOX_TIMESTAMP="$("${IRONFOX_DATE}" -d "${IRONFOX_STAMP}" +"%Y-%m-%dT%H:%M:%SZ")"
|
|
|
|
# Override the timestamps for each file to match our stamp above
|
|
"${IRONFOX_FIND}" "${target_dir}" -newermt "${IRONFOX_FIND_STAMP}" -print0 |
|
|
"${IRONFOX_XARGS}" -0r "${IRONFOX_TOUCH}" -h -d "${IRONFOX_TIMESTAMP}"
|
|
|
|
# Override the timestamps for each directory to match our stamp above
|
|
for dir in $("${IRONFOX_FIND}" "${target_dir}" -type d); do
|
|
"${IRONFOX_TOUCH}" -r "${dir}/$("${IRONFOX_LS}" -At "${dir}" | "${IRONFOX_HEAD}" -n 1)" "${dir}"
|
|
done
|
|
|
|
# By default, we know the archive creation has not failed...
|
|
local archive_failed=0
|
|
|
|
# Finally create our archive
|
|
echo_red_text "Creating archive: ${output_archive} from path: ${target_dir}..."
|
|
pushd "${target_dir}"
|
|
if [[ "${archive_format}" == 'zip' ]]; then
|
|
# shellcheck disable=SC2035
|
|
"${IRONFOX_ZIP}" -X -r "${output_archive}" * -x '.DS_Store' || local archive_failed=1
|
|
elif [[ "${archive_format}" == 'tar' ]]; then
|
|
# shellcheck disable=SC2035
|
|
"${IRONFOX_TAR}" -cJv --exclude-vcs --group=0 --mode='go+u,go-w' --no-acls --no-selinux --no-xattrs --numeric-owner --owner=0 --pax-option='delete=atime,delete=ctime' --pax-option='exthdr.name=%d/PaxHeaders/%f' --restrict --sort=name --utc --clamp-mtime --mtime="${IRONFOX_TIMESTAMP}" --exclude ".DS_Store" -f "${output_archive}" * || local archive_failed=1
|
|
else
|
|
echo_red_text "ERROR: Invalid archive format: '${archive_format}'!"
|
|
exit 1
|
|
fi
|
|
popd
|
|
|
|
# Ensure the archive we just created is valid
|
|
if [[ "${archive_failed}" != 1 ]]; then
|
|
verify_file "${output_archive}" || local archive_failed=1
|
|
fi
|
|
|
|
# If the archive creation failed, return
|
|
if [[ "${archive_failed}" == 1 ]]; then
|
|
echo_red_text "ERROR: Unable to create archive: '${output_archive}' from path: '${target_dir}'!"
|
|
return 1
|
|
else
|
|
echo_green_text "SUCCESS: Created archive: '${output_archive}' from path: '${target_dir}'!"
|
|
fi
|
|
}
|
|
|
|
# Extract an archive
|
|
function extract_archive() {
|
|
function print_usage() {
|
|
echo "Usage: extract_archive 'path/to/archive' 'path/to/extract/archive/to'"
|
|
}
|
|
|
|
if [[ -z "${1+x}" ]]; then
|
|
echo_red_text 'ERROR: Please provide the path to an archive to extract!'
|
|
print_usage
|
|
exit 1
|
|
fi
|
|
|
|
if [[ -z "${2+x}" ]]; then
|
|
echo_red_text 'ERROR: Please provide the path that the archive should be extracted to!'
|
|
print_usage
|
|
exit 1
|
|
fi
|
|
|
|
# Ensure we have basename
|
|
verify_exec "${IRONFOX_BASENAME}" 'IRONFOX_BASENAME' || exit 1
|
|
|
|
# Ensure we have cp
|
|
verify_exec "${IRONFOX_CP}" 'IRONFOX_CP' || exit 1
|
|
|
|
# Ensure we have ls
|
|
verify_exec "${IRONFOX_LS}" 'IRONFOX_LS' || exit 1
|
|
|
|
# Ensure we have mkdir
|
|
verify_exec "${IRONFOX_MKDIR}" 'IRONFOX_MKDIR' || exit 1
|
|
|
|
# Ensure we have rm
|
|
verify_exec "${IRONFOX_RM}" 'IRONFOX_RM' || exit 1
|
|
|
|
local -r archive_path="$1"
|
|
local -r target_path="$2"
|
|
|
|
if [[ ! -f "${archive_path}" ]]; then
|
|
echo_red_text "ERROR: Archive does not exist: '${archive_path}'!"
|
|
exit 1
|
|
fi
|
|
|
|
# Set a temporary archive name
|
|
local -r temp_archive_path_name=$("${IRONFOX_BASENAME}" "${target_path}")
|
|
local -r temp_archive_path="${IRONFOX_EXTERNAL}/temp/${temp_archive_path}"
|
|
|
|
# If our temporary directory for extraction already exists, delete it
|
|
if [[ -d "${temp_archive_path}" ]]; then
|
|
"${IRONFOX_RM}" -rf "${temp_archive_path}"
|
|
fi
|
|
|
|
# Extract based on file extension
|
|
case "${archive_path}" in
|
|
*.zip)
|
|
local -r archive_format='zip'
|
|
;;
|
|
*.tar.gz)
|
|
local -r archive_format='tar.gz'
|
|
;;
|
|
*.tar.xz)
|
|
local -r archive_format='tar.xz'
|
|
;;
|
|
*.tar.zst)
|
|
local -r archive_format='tar.zst'
|
|
;;
|
|
*)
|
|
echo_red_text "ERROR: Unsupported archive format: '${archive_path}'!"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
if [[ "${archive_format}" == 'zip' ]]; then
|
|
# Ensure we have unzip
|
|
verify_exec "${IRONFOX_UNZIP}" 'IRONFOX_UNZIP' || exit 1
|
|
else
|
|
# Ensure we have GNU tar
|
|
verify_exec "${IRONFOX_TAR}" 'IRONFOX_TAR' || exit 1
|
|
fi
|
|
|
|
# Create temporary directory for extraction
|
|
"${IRONFOX_MKDIR}" -p "${temp_archive_path}"
|
|
|
|
# By default, we know the extraction has not failed...
|
|
local extraction_failed=0
|
|
|
|
# Extract our archive
|
|
echo_red_text "Extracting archive: '${archive_path}' to path: '${target_path}'..."
|
|
if [[ "${archive_format}" == 'zip' ]]; then
|
|
"${IRONFOX_UNZIP}" -q "${archive_path}" -d "${temp_archive_path}" || local extraction_failed=1
|
|
elif [[ "${archive_format}" == 'tar.gz' ]]; then
|
|
"${IRONFOX_TAR}" xzf "${archive_path}" -C "${temp_archive_path}" || local extraction_failed=1
|
|
elif [[ "${archive_format}" == 'tar.xz' ]]; then
|
|
"${IRONFOX_TAR}" xJf "${archive_path}" -C "${temp_archive_path}" || local extraction_failed=1
|
|
elif [[ "${archive_format}" == 'tar.zst' ]]; then
|
|
"${IRONFOX_TAR}" --zstd -xvf "${archive_path}" -C "${temp_archive_path}" || local extraction_failed=1
|
|
else
|
|
echo_red_text "ERROR: Invalid archive format: '${archive_format}'!"
|
|
exit 1
|
|
fi
|
|
|
|
local -r top_input_dir=$("${IRONFOX_LS}" "${temp_archive_path}")
|
|
"${IRONFOX_CP}" -rf "${temp_archive_path}/${top_input_dir}/" "${target_path}" || local extraction_failed=1
|
|
|
|
# Ensure the directory we just extracted the archive to is valid
|
|
if [[ "${extraction_failed}" != 1 ]] && [[ ! -d "${target_path}" ]]; then
|
|
local extraction_failed=1
|
|
fi
|
|
|
|
# Clean-up
|
|
"${IRONFOX_RM}" -rf "${temp_archive_path}"
|
|
|
|
# If the extraction failed, return
|
|
if [[ "${extraction_failed}" == 1 ]]; then
|
|
echo_red_text "ERROR: Unable to extract archive: '${archive_path}' to path: '${target_path}'!"
|
|
return 1
|
|
else
|
|
echo_green_text "SUCCESS: Extracted archive: '${archive_path}' to path: '${target_path}'!"
|
|
fi
|
|
}
|