Files
init.sh/lib/filefct.sh
2022-06-24 17:52:17 +02:00

322 lines
9.0 KiB
Bash

# ------------------------------------------------------------------------------
# File manipulation function
# This file is part of the init.sh project
# Copyright (c) 2019-2022 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
# ------------------------------------------------------------------------------
# This file is distributed under 3-clause BSD license.
# The complete license agreement can be obtained at:
# https://opensource.org/licenses/BSD-3-Clause
# ------------------------------------------------------------------------------
# Some useful variables:
export HOST_REPO_PATH=${HOST_REPO_PATH:-"$MYPATH/repo/hosts/$HOSTNAME"}
export GROUP_REPO_PATH=${GROUP_REPO_PATH:-"$MYPATH/repo/groups"}
export COMM_REPO_PATH=${COMM_REPO_PATH:-"$MYPATH/repo/common"}
# ------------------------------------------------------------------------------
# Backup original installation files
# (or any old files if runned several time on same file)
backup_dist()
{
if [[ $# -lt 1 ]]; then
prnt E "backup_dist(): At least one argument is required."
exit 11
fi
local file=
for file in $@; do
local tmstmp=$(stdtime)
if [[ -L ${file} ]]; then
# With symbolik links we call again backup_dist to treat target
prnt I "Following the symbolic link $file to do a proper backup..."
backup_dist $(readlink -f ${file})
elif [[ -f ${file} ]]; then
prnt I "Creating a backup of ${file} on $tmstmp..."
cp -av $file ${file}.dist.${tmstmp}
if [[ $? -ne 0 ]]; then
prnt E "backup_dist(): Failed copying file."
die 12
fi
elif [[ -d ${file} ]]; then
prnt I "Creation a backup of the directory ${file} on $tmstmp..."
cp -av $file ${file}.dist.${tmstmp}
if [[ $? -ne 0 ]]; then
prnt E "backup_dist(): Failed copyind directory recursively."
die 12
fi
else
prnt W "backup_dist(): $file don't exists, nothing to do."
fi
unset tmstmp
done
unset file
}
export -f backup_dist
# ------------------------------------------------------------------------------
# Select source file according to our priority mechanism
select_file()
{
local infile=$1
if [[ -f $HOST_REPO_PATH/$infile ]]; then
local source="$HOST_REPO_PATH/$infile"
elif [[ -f $COMM_REPO_PATH/$infile ]]; then
local source="$COMM_REPO_PATH/$infile"
else
# Not found in repository, we expect full name
local source="$infile"
fi
unset infile
echo $source
unset source
}
export -f select_file
# ------------------------------------------------------------------------------
# Select source directory according to our priority mechanism
select_directory()
{
local indir=$1
if [[ -d $HOST_REPO_PATH/$indir ]]; then
local source="$HOST_REPO_PATH/$indir"
elif [[ -d $COMM_REPO_PATH/$indir ]]; then
local source="$COMM_REPO_PATH/$indir"
else
# Not found in repository, we expect full name
local source="$indir"
fi
unset indir
echo $source
unset source
}
export -f select_directory
# ------------------------------------------------------------------------------
# Install file to the host (specific first then general)
# Todo: implement wildcard support
install_file()
{
local filelist=""
local i=0
if [[ $# -lt 2 ]]; then
prnt E "install_file(): At least two arguments are required."
die 11
fi
if [[ $(echo $@ | grep "\*\|\?") ]]; then
prnt E "install_file(): Wildcards are not authorized."
die 7
fi
local arg=
for arg in $@; do
filelist="$filelist $(select_file $arg)"
done
unset arg
# Empty to just obtain the target which is the last element of the list
local file=
for file in $filelist; do
:
done
if [[ ! $file == /* ]]; then
prnt E "install_file(): Target must be on the root filesystem and full path must be provided."
die 13
fi
unset file
if [[ -d $(dirname $i) ]]; then
prnt I "Creating required target directory $(dirname $i)..."
mkdir -pv $(dirname $i)
if [[ $? -ne 0 ]]; then
prnt E "install_file(): Can't create target directory!"
die 12
fi
fi
prnt I "Copying files ${filelist} to target directory $(dirname $i)..."
cp -av $filelist
if [[ $? -ne 0 ]]; then
prnt E "install_file(): Couldn't copy some required files!"
die 12
fi
}
export -f install_file
# ------------------------------------------------------------------------------
# Add the content of a file at the end of an other
append_file()
{
local srcfile=$(select_file $1)
local dstfile=$2
if [[ -e $dstfile ]]; then
prnt E "append_file(): Target must be on the root filesystem and full path must be provided."
die 13
fi
if [[ ! $dstfile == /* ]]; then
prnt E "append_file(): Target file must exist."
die 13
fi
prnt I "Adding content to file $dstfile..."
cat $srcfile >> $dstfile
if [[ $? -ne 0 ]]; then
prnt E "append_file(): Couldn't append a file!"
die 12
fi
}
export -f append_file
# ------------------------------------------------------------------------------
# determine if a directory is empty
is_dir_empty()
{
dir=$1
if [[ -f $dir ]]; then
prnt E "is_dir_empty(): The given parameter is not a directory."
die 15
fi
if [[ ! -d $dir ]]; then
return 0
fi
nbfiles=$(ls -a1 $dir | egrep -v '^.$|^..$' | wc -l)
if [[ $nbfiles -eq 0 ]]; then
return 0
fi
return 1
}
export -f is_dir_empty
# ------------------------------------------------------------------------------
# copy and patch a file replacing all @var@ by the corresponding value in
# the environment or the variable list given in parameter
patch_file()
{
local srcfile=$(select_file $1) && shift
local dstfile=$1 && shift
local workfile=${dstfile}.work
if [[ ! -s $srcfile ]]; then
prnt E "patch_file(): Source file is empty, is not a file or don't exists!"
die 10
fi
# Create a sub-process, to avoid bash environment pollution
(
local varlist= pattern=
if [[ $# -eq 0 ]] ; then
pattern="-e s/<\(.*\)>/\$\1\$\1/g"
else
local var=
for var in $* ; do
if ! declare -p $var >/dev/null 2>&1 ; then
local $var=$(eval echo \$$var)
fi
export $var
pattern="$pattern -e s/@$var@/\$$var/g"
varlist=$varlist\$$var
done
fi
# sed replace <VAR> with \$$VAR and envsubst do the replace by value
sed $pattern $srcfile | envsubst ${varlist:+"$varlist"} > "$workfile"
)
local -a rights=( $(stat --printf="%a %u %g" "$srcfile") )
unset srcfile
mv "$workfile" "$dstfile"
chmod ${rights[0]} "$dstfile"
chown ${rights[1]}:${rights[2]} "$dstfile"
unset rights dstfile
}
export -f patch_file
# ------------------------------------------------------------------------------
# Put a small header in a file showing it have been automatically modified
tag_file()
{
for f in $@; do
local text="# File automatically modified by init.sh on $(stdtime)."
if [[ -e $f ]]; then
sed -i "1s/^/$text\n/" $f
else
echo $text > $f
sed -i -e "s/modified/generated/" $f
fi
done
}
export -f tag_file
# ------------------------------------------------------------------------------
# check files exists and return 1 if one do not
file_exists()
{
for f in $@; do
if [[ ! -f $(select_file $f) ]]; then
echo $f
return 1
fi
done
return 0
}
export -f file_exists
# ------------------------------------------------------------------------------
# check if file exists and return error if not
file_must_exists()
{
prnt I "Checking $@ files existance..."
local mf=$(file_exists $@)
if [[ $? -ne 0 ]]; then
prnt E "file_must_exists(): The $mf file is missing, can't continue."
die 10
fi
unset mf
}
export -f file_must_exists
# ------------------------------------------------------------------------------
# check files exists and return 1 if one do not
directory_exists()
{
for d in $@; do
if [[ ! -d $(select_directory $d) ]]; then
echo $d
return 1
fi
done
return 0
}
export -f directory_exists
# ------------------------------------------------------------------------------
# check if file exists and return error if not
directory_must_exists()
{
prnt I "Checking $@ directories existance..."
local md=$(directory_exists $@)
if [[ $? -ne 0 ]]; then
prnt E "directory_must_exists(): The $md directory is missing, can't continue."
die 10
fi
unset md
}
export -f directory_must_exists
# EOF