#!/bin/sh -e # # Ansible Boilerplate Collection: Setup & Maintenance Script. # # Detect commands to use: PYTHON="${PYTHON:-$(command -v python3 2>/dev/null || echo "python3")}" PIP="${PIP:-$(command -v pip 2>/dev/null || echo "pip")}" ANSIBLE_GALAXY="${ANSIBLE_GALAXY:-$(command -v ansible-galaxy 2>/dev/null || echo "ansible-galaxy")}" BASE_D="ansible_galaxy/ansible_collections/alexbarton/boilerplate" # # Show usage information on stderr. # Usage() { { echo "$0 " echo echo " help Show this help text and exit." echo " init Initialize project and boilerplate code." echo " upgrade Upgrade boilerplate code and dependencies. [Alias: update, up]" echo " --force Force overwriting an existing role or collection." echo } >&2 } # # Initialize a new project. # # Create some default files and call Upgrade() afterwards. This function does not # overwrite any already existing file. # Init() { if [ $# -ne 0 ]; then Usage exit 1 fi if [ -e Makefile.boilerplate ]; then echo "This is the upstream project! Don't call \"init\" on it!" >&2 exit 1 fi echo "Initialize project:" for file in \ README.md \ LICENSE \ ; do test -e "${file}" || touch "${file}" done mkdir -p .vscode playbooks roles test -e "hosts.ini" || Init_HostsIni test -e "Makefile" || Init_Makefile test -e "requirements.yml" || Init_RequirementsYml Upgrade --init } # # Create a Makefile template file. # Init_Makefile() { echo "Creating \"Makefile\" ..." cat >Makefile <&2) default: all # Include the Ansible Boilerplate Collection Makefile fragment: include ansible_galaxy/ansible_collections/alexbarton/boilerplate/Makefile.boilerplate all: check: install: clean: distclean: clean maintainer-clean: distclean .PHONY: default all check install clean distclean maintainer-clean EOF } # # Create a hosts.ini template file. # Init_HostsIni() { echo "Creating \"hosts.ini\" ..." cat >hosts.ini <requirements.yml </dev/null; then # Either an existing ".venv" folder was found or the # ansible-galaxy(1) command was not found on the system, so # let's use a Python virtual environment! echo "Using a Python virtual environment." PIP="./.venv/bin/pip" ANSIBLE_GALAXY="./.venv/bin/ansible-galaxy" if ! [ -x .venv/bin/pip ]; then echo "Initializing Python virtual environment ..." "${PYTHON}" -m venv .venv "${PIP}" install -U pip setuptools fi fi for var in PYTHON PIP ANSIBLE_GALAXY; do eval 'echo " - ${var} is \"$'"${var}"'\"."' done if ! [ -x "${ANSIBLE_GALAXY}" ]; then echo "Installing Ansible ..." "${PIP}" install -U ansible fi # Are we running in a dependent project? If so, perform specific upgrade tasks! # shellcheck disable=SC2086 [ -e Makefile.boilerplate ] || Upgrade_Dependent ${is_init} if [ -r requirements.txt ]; then echo "Installing Python dependencies ..." "${PIP}" install -U -r requirements.txt fi if [ -r requirements.yml ]; then echo "Upgrading Ansible Galaxy dependencies ..." # shellcheck disable=SC2248 "${ANSIBLE_GALAXY}" collection install -U -r requirements.yml ${do_force} # shellcheck disable=SC2248 "${ANSIBLE_GALAXY}" role install -r requirements.yml ${do_force} fi } # # Upgrade steps for dependent projects only. # # --init: Upgrade() is called by the Init() function. # Upgrade_Dependent() { collection="${BOILERPLATE_COLLECTION_SRC:-alexbarton.boilerplate}" echo "Installing/upgrading \"${collection}\" ..." "${ANSIBLE_GALAXY}" collection install -U -p ansible_galaxy "${collection}" echo "Copying \"boilerplate\" script into bin/ directory ..." mkdir -p bin cp -av "${BASE_D}/bin/ansible-boilerplate" "bin/ansible-boilerplate" echo "Creating symbolic links to files inside of the Boilerplate Collection ..." for file in \ bin/a \ bin/ap \ bin/aps \ ; do # Create (new) symbolic links, when the target already is a symbolic link or # does not yet exists. Don't overwrite existing regular files etc.! test -L "${file}" && ln -fsv "../${BASE_D}/${file}" "${file}" test -e "${file}" || ln -fsv "../${BASE_D}/${file}" "${file}" done echo "Upgrading template files from the Boilerplate Collection ..." for file in \ .ansible-lint \ .editorconfig \ .gitignore \ .vscode/settings.json \ .yamllint.yml \ ansible.cfg \ requirements.txt \ ; do # shellcheck disable=SC2086 Upgrade_Template "${file}" ${is_init} done # Verify that the Boilerplate Collection is available now! "${ANSIBLE_GALAXY}" collection verify --offline alexbarton.boilerplate } # # Upgrade a template file. # # --init: Initialize a new project, therefore create the template file if it # does not yet exist. # Upgrade_Template() { # Does the target directory exist? Skip this template file if not! [ -d "$(dirname "$1")" ] || return 0 # Return when the target file does not exist and not in "init mode": [ ! -e "$1" ] && [ "$2" != "--init" ] && return 0 # Remove the target when it is a symbolic link. [ -L "$1" ] && rm -v "$1" # Do not override the target when it exists already! if [ -e "$1" ]; then # Target already exists. Is it different? if ! cmp "$1" "${BASE_D}/$1"; then # Files are not the same! Install new version in parallel: install -b -m 0644 -p -v "${BASE_D}/$1" "$1.new" fi else # Target does not yet exist: install -b -m 0644 -p -v "${BASE_D}/$1" "$1" fi } cmd="$1" [ $# -gt 0 ] && shift case "${cmd}" in "init") Init "$@" ;; "upgrade"|"update"|"up") Upgrade "$@" ;; "help"|"--help") Usage ;; *) Usage exit 1 esac exit 0