diff --git a/contrib/hooks/post_encrypt b/contrib/hooks/post_encrypt new file mode 100755 index 0000000..bc4cbf6 --- /dev/null +++ b/contrib/hooks/post_encrypt @@ -0,0 +1,96 @@ +#!/usr/bin/env bash + +# yadm - Yet Another Dotfiles Manager +# Copyright (C) 2015-2019 Tim Byrne and Martin Zuther + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +YADM_CHECKSUMS="$YADM_HOOK_DIR/files.checksums" +WARNING_MESSAGE="No checksums were created" + +# unpack exported array; filenames including a newline character (\n) +# are NOT supported +OLD_IFS="$IFS" +IFS=$'\n' +YADM_ENCRYPT_INCLUDE_FILES=( $YADM_ENCRYPT_INCLUDE_FILES ) +IFS="$OLD_IFS" + + +function get_checksum_command { + # check if "shasum" exists and supports the algorithm (which is + # tested by sending an empty string to "shasum") + if command -v "shasum" > /dev/null && printf "" | shasum --algorithm "256" &> /dev/null; then + printf "shasum --algorithm 256" + # check if "sha256sum" exists + elif command -v "sha256sum" > /dev/null; then + printf "sha256sum" + # check if "gsha256sum" exists + elif command -v "gsha256sum" > /dev/null; then + printf "gsha256sum" + else + # display warning in bright yellow + printf "\033[1;33m" >&2 + printf "\nWARNING: \"shasum\", \"sha256sum\" and \"gsha256sum\" not found. %s\n" "$WARNING_MESSAGE." >&2 + + # reset output color + printf "\033[0m" >&2 + + # signal error + return 1 + fi +} + + +# get checksum command +CHECKSUM_COMMAND=$(get_checksum_command) + +# no command found +if (($?)); then + # return original exit status of yadm command + exit "$YADM_HOOK_EXIT" +fi + +# empty (or create) checksum file +true > "$YADM_CHECKSUMS" + +# calculate checksums for encrypted files +for included in "${YADM_ENCRYPT_INCLUDE_FILES[@]}"; do + # highlight any errors in red + printf "\033[0;31m" + + # calculate checksums + $CHECKSUM_COMMAND "$included" >> "$YADM_CHECKSUMS" + ERROR_CODE=$? + + # reset output color + printf "\033[0m" + + # handle errors + if (($ERROR_CODE)); then + # display warning in bright yellow + printf "\033[1;33m" >&2 + printf "\nWARNING: an error occurred. Please inspect the checksum file.\n" >&2 + + # reset output color + printf "\033[0m" >&2 + + # exit and signal error + exit $ERROR_CODE + fi +done + +# announce success and return original exit status of yadm command +printf "Wrote SHA-256 checksums: %s\n" "$YADM_CHECKSUMS" +exit "$YADM_HOOK_EXIT" diff --git a/contrib/hooks/post_list b/contrib/hooks/post_list new file mode 100755 index 0000000..b95acc2 --- /dev/null +++ b/contrib/hooks/post_list @@ -0,0 +1,69 @@ +#!/usr/bin/env bash + +# yadm - Yet Another Dotfiles Manager +# Copyright (C) 2015-2019 Tim Byrne and Martin Zuther + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +YADM_CHECKSUMS="$YADM_HOOK_DIR/files.checksums" + + +# is current directory on yadm's work path? +# (adapted from https://unix.stackexchange.com/a/6438/122163) +if [ "${PWD##$YADM_HOOK_WORK}" != "$PWD" ]; then + ON_WORK_PATH=1 +else + ON_WORK_PATH=0 +fi + + +# list all files or only those in the subdirectories below? +OPTION_LIST_ALL=0 +for argument in "${YADM_HOOK_FULL_COMMAND[@]}"; do + # mimick git ls-files by displaying all files when not on work + # path + if [ "$argument" = "-a" ] || [ $ON_WORK_PATH -eq 0 ]; then + OPTION_LIST_ALL=1 + break + fi +done + + +# if there is no checksum file, exit with original status of yadm +# command +if [ ! -f "$YADM_CHECKSUMS" ]; then + exit "$YADM_HOOK_EXIT" +fi + +# list encrypted files +while IFS= read -r filename; do + # remove checksums from file names + filename="${filename##[a-zA-Z0-9]* }" + + # list only files in the subdirectories below (i.e. files + # whose relative path doesn't begin with "../") + if [ $OPTION_LIST_ALL -eq 0 ]; then + REL_PATH=$(relative_path "$PWD" "$YADM_HOOK_WORK/$filename") + + if [ "$REL_PATH" = "${REL_PATH##../}" ]; then + printf "%s\n" "$REL_PATH" + fi + # list all files + else + printf "%s\n" "$filename" + fi +done < "$YADM_CHECKSUMS" + +# return original exit status of yadm command +exit "$YADM_HOOK_EXIT" diff --git a/contrib/hooks/post_status b/contrib/hooks/post_status new file mode 100755 index 0000000..3dd0465 --- /dev/null +++ b/contrib/hooks/post_status @@ -0,0 +1,100 @@ +#!/usr/bin/env bash + +# yadm - Yet Another Dotfiles Manager +# Copyright (C) 2015-2019 Tim Byrne and Martin Zuther + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +YADM_CHECKSUMS="$YADM_HOOK_DIR/files.checksums" +WARNING_MESSAGE="Checksums were not verified" + +# unpack exported array; filenames including a newline character (\n) +# are NOT supported +OLD_IFS="$IFS" +IFS=$'\n' +YADM_ENCRYPT_INCLUDE_FILES=( $YADM_ENCRYPT_INCLUDE_FILES ) +IFS="$OLD_IFS" + + +function get_checksum_command { + # check if "shasum" exists and supports the algorithm (which is + # tested by sending an empty string to "shasum") + if command -v "shasum" > /dev/null && printf "" | shasum --algorithm "256" &> /dev/null; then + printf "shasum --algorithm 256" + # check if "sha256sum" exists + elif command -v "sha256sum" > /dev/null; then + printf "sha256sum" + # check if "gsha256sum" exists + elif command -v "gsha256sum" > /dev/null; then + printf "gsha256sum" + else + # display warning in bright yellow + printf "\033[1;33m" >&2 + printf "\nWARNING: \"shasum\", \"sha256sum\" and \"gsha256sum\" not found. %s\n" "$WARNING_MESSAGE." >&2 + + # reset output color + printf "\033[0m" >&2 + + # signal error + return 1 + fi +} + + +# if there is no checksum file, exit with original status of yadm +# command +if [ ! -f "$YADM_CHECKSUMS" ]; then + exit "$YADM_HOOK_EXIT" +fi + +# get checksum command +CHECKSUM_COMMAND=$(get_checksum_command) + +# no command found +if (($?)); then + # return original exit status of yadm command + exit "$YADM_HOOK_EXIT" +fi + +# check encrypted files for differences and capture output and error +# messages +YADM_CHECKSUM_OUTPUT=$($CHECKSUM_COMMAND --check "$YADM_CHECKSUMS" 2>&1) +ERROR_CODE=$? + +# handle mismatched checksums and errors +if (($ERROR_CODE)); then + printf "\nSome SHA-256 sums do not match (or an error occurred):\n\n" + + # display differing files and errors (highlighted in red) + printf "\033[0;31m" + + while IFS= read -r line; do + # beautify output and get rid of unnecessary lines + line="${line%%*: [Oo][Kk]}" + line="${line%%: [Ff][Aa][Ii][Ll][Ee][Dd]}" + line="${line##*WARNING:*did NOT match}" + + if [ -n "$line" ]; then + printf "%s\n" "$line" + fi + done <<< "$YADM_CHECKSUM_OUTPUT" + + # reset output color + printf "\033[0m" + + # display advice for differing files and signal error + printf "\nConsider running either \"yadm encrypt\" or \"yadm decrypt\".\n" + exit $ERROR_CODE +fi diff --git a/yadm b/yadm index b8f42fd..f164b16 100755 --- a/yadm +++ b/yadm @@ -1573,15 +1573,29 @@ function invoke_hook() { # expose some internal data to all hooks YADM_HOOK_COMMAND=$HOOK_COMMAND + YADM_HOOK_DIR=$YADM_DIR YADM_HOOK_EXIT=$exit_status YADM_HOOK_FULL_COMMAND=$FULL_COMMAND YADM_HOOK_REPO=$YADM_REPO YADM_HOOK_WORK=$YADM_WORK + + # pack array to export it; filenames including a newline character (\n) + # are NOT supported + YADM_ENCRYPT_INCLUDE_FILES=$(join_string $'\n' "${ENCRYPT_INCLUDE_FILES[@]}") + export YADM_HOOK_COMMAND + export YADM_HOOK_DIR export YADM_HOOK_EXIT export YADM_HOOK_FULL_COMMAND export YADM_HOOK_REPO export YADM_HOOK_WORK + export YADM_ENCRYPT_INCLUDE_FILES + + # export helper functions + export -f builtin_dirname + export -f relative_path + export -f unix_path + export -f mixed_path "$hook_command" hook_status=$? @@ -1819,6 +1833,13 @@ function auto_bootstrap() { } +# ****** Helper Functions ****** + +function join_string { + local IFS="$1" + printf "%s" "${*:2}" +} + # ****** Prerequisites Functions ****** function require_archive() { @@ -1886,7 +1907,7 @@ function readlink_available() { return 1 } -# ****** Directory tranlations ****** +# ****** Directory translations ****** function unix_path() { # for paths used by bash/yadm @@ -1906,6 +1927,7 @@ function mixed_path() { } # ****** echo replacements ****** + function echo() { IFS=' ' printf '%s\n' "$*"