#!/bin/bash

# script: make_config.d.sh
#
# generate a config file from many different parts.
#
# Given a configuration file /etc/foo, this script will generate
# that file from the files in /etc/foo.d/.
# If there are any changes from the current /etc/foo, it will
# backup the current /etc/foo to /etc/foo.bak/foo_YYYY.MM.DD.HH:MM:SS
# before overwriting it with the new config.
# All comments and blank lines are stripped
#
# If you want the files in /etc/foo.d/ to be inserted into /etc/foo
# in a particular order, name the files so that an alphanumeric
# sort lists them in the right order.
# eg:
#    10first_file.txt
#    20second_file.txt
#    25third_file.txt


# this script takes one argument - the name of the conf file
# to generate from the conf.d directory.  If there is a change
# to the file, the previous file is backed up.

# input: filename
# generated from: filename.d/*
# backups put in: filename.bak/*

# set this to "true" to enable backups.  Any other value disables them.
BACKUP_FILES="true"

verbosity=5
me=$0

VERSION=1.1



CRITICAL=1
WARNING=3
ERROR=4
INFO=5
VERBOSE=6
DEBUG=7
EVERYTHING=8
function myprintf () {
  level=$1
  shift
  format="$1"
  shift
  if [ $verbosity -ge $level ]
  then
        if [ $level -ge 7 ]
        then
                # print debugging messages in red
                format="\033[0;31m${format}\033[0m"
        fi
    printf "$format" "$@"
  fi
}
function usage() {
	myprintf $INFO "USAGE: ${me} [OPTIONS]... FILENAME\n"
	myprintf $INFO "	-v	increase verbosity\n"
	myprintf $INFO "	-q	decrease verbosity\n"
	myprintf $INFO "	-d	debugging (very verbose)\n"
	myprintf $INFO "	--help	Display this help and exit\n"
	myprintf $INFO "	FILENAME - configuration file to generate (required)\n"
	myprintf $INFO "	\n"
	myprintf $INFO "	This script generates a file (FILENAME) from the components \n"
	myprintf $INFO "	in FILENAME.d/*  It removes comments and blank lines in the \n"
	myprintf $INFO "	target file.  It backs up changed versions to FILENAME.bak/\n"
	myprintf $INFO "	\n"
	my_exit 0
}

function my_exit() {
	if [[ "k$new_file" != "k" && -e $new_file ]]
	then
		myprintf 7 "deleting temp file $new_file... "
		rm $new_file
		myprintf 7 "Done.\n"
	fi
	exit $1
}


while [ $# -gt 0 ]
do
        case "$1" in
                -*=*)
                        optarg=$(echo "$1" | sed 's/[-_a-zA-Z0-9]*=//')
                        ;;
                *)
                        optarg=
                        ;;
        esac
        case "$1" in
				-v) let "verbosity += 1" ;;
				-vv) let "verbosity += 2" ;;
				-q) let "verbosity -= 1" ;;
				-qq) let "verbosity -= 2" ;;
				-d) verbosity=7 ;;
				-V) echo "Version: $VERSION" ; my_exit 0 ;;
				--verbosity=*)
						verbosity=$optarg
						;;
                --help)
                        usage
                        exit 0
                        ;;
                --)
                        shift
                        break
                        ;;
                -*)
                        die "invalid option $1"
                        ;;
                *)
                        break
                        ;;
        esac
        shift
done

if [ $verbosity -lt 0 ] ; then verbosity=0 ; fi

date=`date +%Y.%m.%d.%H:%M:%S`

file=$1

if [ "k${file}" == "k" ]
then
	myprintf $INFO "One argument needed - the file to generate\n"
	my_exit 1
fi

bfile=`basename ${file}`
dfile=`dirname ${file}`
new_file=/tmp/${bfile}.$$

cat <<EOF >${new_file}
###
###   DO NOT EDIT THIS FILE!!!
###
###   This file is generated from the contents of the
###   ${bfile}.d/ directory.  Edit the files there instead.
###   Any changes you make here *will* get wiped out next
###   time the update runs.
###
###   generated by $0
###

EOF

files=`find ${file}.d/ | sort`
for f in ${files}
do
	if [ -f $f ]
	then
		#concatonate all files without comments or spaces
		myprintf $INFO "" >> $new_file
		myprintf $INFO "# settings from ${f}" >> $new_file
		cat $f | grep -v "^$" | egrep -v "^\W*#" >> $new_file
	fi
done

diff -q ${file} $new_file > /dev/null 2>&1
res=$?
if [ $res -eq 0 ]
then
	myprintf $INFO "The file I just generated is the same as the file that is currently in place.\n"
	myprintf $INFO "I am not going to replace it.\n"
	myprintf $INFO "\n"
	my_exit 0
else
	# if the file currently exists and we're supposed to do backups, back it up.
	if [[ -e ${file} && $BACKUP_FILES == "true" ]]
	then
		myprintf $INFO "backing up ${file} to ${file}.bak/${bfile}_${date}... "
		# if the backup dir doesn't exist, create it
		if [ ! -e ${file}.bak ]
		then
			mkdir ${file}.bak
			res=$?
			if [ $res -ne 0 ]
			then
				myprintf $INFO "Failed.\n"
				myprintf $INFO "The backup directory ${file}.bak didn't exist and I couldn't make it.\n"
				myprintf $INFO "Cancelling operation... your original file \"${file}\" is intact.\n"
				my_exit 1
			fi
		fi
		# if the backup dir isn't a directory, cancel.
		if [ ! -d ${file}.bak ]
		then
			myprintf $INFO "Failed.\n"
			myprintf $INFO "The place where I want to put my backups (${file}.bak) already\n"
			myprintf $INFO "exists, but it's not a directory.  I can't make my backup so I won't go on.\n"
			myprintf $INFO "Cancelling operation... your original file \"${file}\" is intact.\n"
			my_exit 1
		fi
		cp ${file} ${file}.bak/${bfile}_${date}
		res=$?
		if [ $res -eq 0 ]
		then
			myprintf $INFO "Done.\n"
		else
			myprintf $INFO "Failed.\n"
			myprintf $INFO "\n"
			myprintf $INFO "I failed to make a backup of your current config!\n"
			myprintf $INFO "Cancelling operation...  your original file \"${file}\" is intact.\n"
			my_exit 1
		fi
	fi
	myprintf $INFO "moving new ${file} into place... "
	mv $new_file ${file}
	res=$?
	if [ $res -eq 0 ]
	then
		myprintf $INFO "Done.\n"
	else
		myprintf $INFO "Failed.\n"
		myprintf $INFO "\n"
		myprintf $INFO "I failed to new config file into place!\n"
		myprintf $INFO "I'm not sure what the current state of your config is,\n"
		myprintf $INFO "you should go check it by hand.  Sorry...\n"
		my_exit 1
	fi

fi

