#!/bin/bash

# debops-init: create a new DebOps project
# Copyright (C) 2014 Nick Janetakis <nick.janetakis@gmail.com>
# Part of the DebOps project - http://debops.org/

set -e

# ---- Global constants ----

declare -r DEBOPS_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}/debops"
declare -r DEBOPS_CONFIG=".debops.cfg"
declare -r DEBOPS_INVENTORY="inventory"
declare -r SCRIPT_NAME="$(basename ${0})"
declare -r SECRET_NAME="secret"


# ---- Configuration variables ----

NEW_INVENTORY="ansible/${DEBOPS_INVENTORY}"

SKEL_DIRS=(
  "ansible/${DEBOPS_INVENTORY}/group_vars/all"
  "ansible/${DEBOPS_INVENTORY}/host_vars"
  "ansible/playbooks"
)


# ---- Functions ----

# Find specified file or directory in parent dir (if not specified, finds $DEBOPS_CONFIG)
# Source: https://unix.stackexchange.com/questions/13464
find_up () {
  local name=${1:-$DEBOPS_CONFIG}
  local slashes="${PWD//[^\/]/}"
  local directory="${PWD}"

  for (( n=${#slashes}; n>0; --n )) ; do
    test -e "${directory}/${name}" && echo "$(readlink -f ${directory}/${name})" && return
    directory="$directory/.."
  done
}

# Display error message and exit
error_msg () {
  local severity="${2:-Error}"
  local message="${1}"

  echo >&2 "${SCRIPT_NAME}: ${severity}: ${message}"
  set +e
  [[ "${severity}" == "Error" ]] && exit 1
  set -e
}

# Check if required commands exist
require_commands () {
  for name in ${@} ; do
    if ! type ${name} > /dev/null 2>&1 ; then
      error_msg "${name}: command not found"
    fi
  done
}

command_exists () {
  type "$1" &> /dev/null ;
}

# ---- DebOps environment setup ----

# Specify name of new project directory
project="${1:-$PWD}"

# Find DebOps configuration file
debops_config="$(find_up)"

# Check if project dir already exists
new_project="$(find_up ${project})"

# Find root of the DebOps project dir
[ -n "${debops_config}" ] && debops_root="$(dirname ${debops_config})"

# Exit if we are in a DebOps project dir and nested project would be created
if [ -n "${debops_root}" ] ; then
  if [ "${debops_root}" = "${new_project}" ] ; then
    error_msg "You are inside ${new_project} project already"
  else
    [ -z "${project}" ] && error_msg "Cannot create nested project in ${debops_root}"
  fi
fi

# Exit if DebOps configuration file has been found
[ -r "${project}/${DEBOPS_CONFIG}" ] && error_msg "${project} is already a DebOps project"


# ---- Main script ----

echo "Creating new DebOps project in ${project} ..."

# Create base project directories
for skel_dir in "${SKEL_DIRS[@]}" ; do
    mkdir -p ${project}/${skel_dir}
done

# Create .debops.cfg
touch ${project}/${DEBOPS_CONFIG}

# Create .gitignore
[ ! -r ${project}/.gitignore ] && cat <<EOF > ${project}/.gitignore
ansible/${SECRET_NAME}
${SECRET_NAME}
ansible.cfg

### vim ###
[._]*.s[a-w][a-z]
[._]s[a-w][a-z]
*.un~
Session.vim
.netrwhist
*~


### Emacs ###
# -*- mode: gitignore; -*-
\#*\#
/.emacs.desktop
/.emacs.desktop.lock
*.elc
auto-save-list
tramp
.\#*


### SublimeText ###
# workspace files are user-specific
*.sublime-workspace

# project files should be checked into the repository, unless a significant
# proportion of contributors will probably not be using SublimeText
# *.sublime-project

#sftp configuration file
sftp-config.json

EOF

# Swap in different hosts file content depending on the host's OS/distro
valid_debops_controller=0
hosts_file="${project}/${NEW_INVENTORY}/hosts"

if [ $(uname) = "Linux" ]; then
  if command_exists lsb_release ; then
    distro=$(lsb_release -si)
    if [ "${distro}" = "Debian" -o "${distro}" = "Ubuntu" ]; then
      valid_debops_controller=1
    fi
  fi
fi

if [ -r ${hosts_file} ] ; then
    echo
    echo "Hosts file '${hosts_file}' already exists."
    echo "If you want $(basename $0) to create a fresh one, please delete"
    echo "this file manually."
else
    cat <<EOF > ${hosts_file}
# This is an Ansible inventory file in INI format. You can define a list of
# hosts and groups to be managed by this particular inventory.

# Hosts listed under [ansible_controllers] will have common DebOps plays
# ran against them. It will include services such as iptables, DNS, Postfix,
# sshd configuration and more.
#
# View the list here:
# https://github.com/debops/debops-playbooks/blob/master/playbooks/common.yml

EOF

    if [ "$valid_debops_controller" -eq 1 ]; then
	cat <<EOF >> ${hosts_file}
# Your host is eligible to be managed by DebOps' common playbook. If you want
# that functionality and more, then uncomment your hostname below.
[ansible_controllers]
#$(hostname) ansible_connection=local

EOF
    else
	cat <<EOF >> ${hosts_file}
# Your host is not Debian-based so you will not be able to leverage
# the above features on your current operating system. You can however
# use Vagrant or something else to setup a VM and install DebOps there.

[ansible_controllers]
#<VM host IP>

EOF
    fi
fi # if ${hosts_file} exists

apt_lxc_file="${project}/${NEW_INVENTORY}/group_vars/all/apt_lxc.yml"

if [ -r ${apt_lxc_file} ] ; then
    echo
    echo "File '${apt_lxc_file}' already exists."
    echo "If you want $(basename $0) to create a fresh one, please delete"
    echo "this file manually."
else
    cat <<EOF > ${apt_lxc_file}
# Occasionally Debian's CDN is a bit flaky. If you get 404s trying to access
# source URLs then uncomment the 2 variables below. You may also want to use
# your location's mirror rather than US, check the list of mirrors here:
#
# http://debian.mirrors.tds.net/pub/linux/debian/README.mirrors.html
#
#apt_mirrors: [ 'http://ftp.us.debian.org/debian' ]
#lxc_template_debootstrap_mirror: '{{ apt_mirrors[0] }}'
EOF
fi
