From 708b491d88515ed179de28cf115c802e2e62519d Mon Sep 17 00:00:00 2001 From: Klas Mellbourn Date: Sun, 7 May 2017 22:43:10 +0200 Subject: [PATCH 01/20] fix for getting 'COMP_WORDS bad array subscript' on completing yadm I stared getting these errors when pressing tab after 'yadm '. This seems to be due to COMP_CWORD being negative, so this is the fix I applied --- completion/yadm.bash_completion | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/completion/yadm.bash_completion b/completion/yadm.bash_completion index e538cbc..a9a550f 100644 --- a/completion/yadm.bash_completion +++ b/completion/yadm.bash_completion @@ -9,8 +9,14 @@ if declare -F _git > /dev/null; then _yadm() { local current=${COMP_WORDS[COMP_CWORD]} - local penultimate=${COMP_WORDS[COMP_CWORD-1]} - local antepenultimate=${COMP_WORDS[COMP_CWORD-2]} + local penultimate + if (($COMP_WORDS > 0)); then + penultimate=${COMP_WORDS[COMP_CWORD-1]} + fi + local antepenultimate + if (($COMP_WORDS > 1)); then + antepenultimate=${COMP_WORDS[COMP_CWORD-2]} + fi local GIT_DIR # shellcheck disable=SC2034 From 79e149ed25950f0999dc81dcad599117635cda57 Mon Sep 17 00:00:00 2001 From: Tim Byrne Date: Wed, 10 May 2017 07:55:45 -0500 Subject: [PATCH 02/20] Switch to semantic versioning --- test/100_accept_version.bats | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/100_accept_version.bats b/test/100_accept_version.bats index 8c9b219..962b91f 100644 --- a/test/100_accept_version.bats +++ b/test/100_accept_version.bats @@ -5,7 +5,7 @@ status=;output=; #; populated by bats run() @test "Command 'version'" { echo " When 'version' command is provided, - Print the current version with format 'yadm x.xx' + Print the current version with format 'yadm x.x.x' Exit with 0 " @@ -20,6 +20,6 @@ status=;output=; #; populated by bats run() #; validate status and output [ $status -eq 0 ] [ "$output" = "yadm $VERSION" ] - version_regex="^yadm [[:digit:]\.]+$" + version_regex="^yadm [[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+$" [[ "$output" =~ $version_regex ]] } From 68937f3cad28203d2e7a7a8f5eff01977de6da6f Mon Sep 17 00:00:00 2001 From: Tim Byrne Date: Wed, 10 May 2017 17:44:56 -0500 Subject: [PATCH 03/20] Release 1.10.0 Update version number and update documentation * Fix `COMP_WORDS bad array subscript` bug (#64) * Transition to semantic versioning --- CHANGES | 4 ++++ CONTRIBUTORS | 3 ++- yadm | 2 +- yadm.1 | 2 +- yadm.spec | 6 +++++- 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 8038bca..e73fe44 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +1.10.0 + * Fix `COMP_WORDS bad array subscript` bug (#64) + * Transition to semantic versioning + 1.09 * Add Bash completion script (#60) * Support WSL detection (#61) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 409ba19..b7094cd 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -3,6 +3,7 @@ CONTRIBUTORS Tim Byrne Espen Henriksen Jan Schulz +Paraplegic Racehorse Patrick Hof Satoshi Ohki Siôn Le Roux @@ -10,4 +11,4 @@ Sébastien Gross Tomas Cernaj Uroš Golja Franciszek Madej -Paraplegic Racehorse +Klas Mellbourn diff --git a/yadm b/yadm index d03af71..5787d65 100755 --- a/yadm +++ b/yadm @@ -19,7 +19,7 @@ if [ -z "$BASH_VERSION" ]; then [ "$YADM_TEST" != 1 ] && exec bash "$0" "$@" fi -VERSION=1.09 +VERSION=1.10.0 YADM_WORK="$HOME" YADM_DIR="$HOME/.yadm" diff --git a/yadm.1 b/yadm.1 index 68758a9..a24aa9a 100644 --- a/yadm.1 +++ b/yadm.1 @@ -1,5 +1,5 @@ ." vim: set spell so=8: -.TH yadm 1 "4 May 2017" "1.09" +.TH yadm 1 "10 May 2017" "1.10.0" .SH NAME yadm \- Yet Another Dotfiles Manager .SH SYNOPSIS diff --git a/yadm.spec b/yadm.spec index 7c90e7b..9fd90d0 100644 --- a/yadm.spec +++ b/yadm.spec @@ -1,6 +1,6 @@ Summary: Yet Another Dotfiles Manager Name: yadm -Version: 1.09 +Version: 1.10.0 Release: 1%{?dist} URL: https://github.com/TheLocehiliosan/yadm License: GPLv3 @@ -37,6 +37,10 @@ install -m 644 yadm.1 ${RPM_BUILD_ROOT}%{_mandir}/man1 %doc CHANGES CONTRIBUTORS README.md completion/yadm.bash_completion %changelog +* Wed May 10 2017 Tim Byrne - 1.10.0-1 +- Bump version to 1.10.0 +- Transition to semantic versioning + * Thu May 4 2017 Tim Byrne - 1.09-1 - Bump version to 1.09 - Add yadm.bash_completion From f8e0bd593dbb5fa8b79cc565f97b20934923d661 Mon Sep 17 00:00:00 2001 From: Tim Byrne Date: Mon, 29 May 2017 00:17:55 -0500 Subject: [PATCH 04/20] Support `yadm.cygwin-copy` configuration (#62) With `yadm.cygwin-copy` set to "true", alternate files will be copies instead of symlinks, but only when running on Cygwin. --- test/115_accept_introspect.bats | 2 +- test/116_accept_cygwin_copy.bats | 102 +++++++++++++++++++++++++++++++ test/common.bash | 12 ++++ yadm | 15 ++++- yadm.1 | 5 ++ 5 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 test/116_accept_cygwin_copy.bats diff --git a/test/115_accept_introspect.bats b/test/115_accept_introspect.bats index c283f6d..0d1922b 100644 --- a/test/115_accept_introspect.bats +++ b/test/115_accept_introspect.bats @@ -73,7 +73,7 @@ function count_introspect() { Exit with 0 " - count_introspect "configs" 0 11 'yadm\.auto-alt' + count_introspect "configs" 0 12 'yadm\.auto-alt' } @test "Command 'introspect' (repo)" { diff --git a/test/116_accept_cygwin_copy.bats b/test/116_accept_cygwin_copy.bats new file mode 100644 index 0000000..07957c9 --- /dev/null +++ b/test/116_accept_cygwin_copy.bats @@ -0,0 +1,102 @@ +load common +load_fixtures + +IN_REPO=(alt*) +export TEST_TREE_WITH_CYGWIN=1 +export SIMULATED_CYGWIN="CYGWIN_NT-6.1-WOW64" + +setup() { + destroy_tmp + build_repo "${IN_REPO[@]}" +} + +test_alt() { + local cygwin_copy="$1" + local is_cygwin="$2" + local expect_link="$3" + + case "$cygwin_copy" in + true|false) + git config --file="$T_YADM_CONFIG" "yadm.cygwin-copy" "$cygwin_copy" + ;; + esac + + if [ "$is_cygwin" = "true" ]; then + echo '#!/bin/sh' > "$T_TMP/uname" + echo "echo $SIMULATED_CYGWIN" >> "$T_TMP/uname" + chmod a+x "$T_TMP/uname" + fi + + local expected_content + expected_content="$T_DIR_WORK/alt-test##$(PATH="$T_TMP:$PATH" uname -s)" + + PATH="$T_TMP:$PATH" run "${T_YADM_Y[@]}" alt + + if [ -L "$T_DIR_WORK/alt-test" ] && [ "$expect_link" != 'true' ] ; then + echo "ERROR: Alt should be a simple file, but isn't" + return 1 + fi + if [ ! -L "$T_DIR_WORK/alt-test" ] && [ "$expect_link" = 'true' ] ; then + echo "ERROR: Alt should use symlink, but doesn't" + return 1 + fi + + if ! diff "$T_DIR_WORK/alt-test" "$expected_content"; then + echo "ERROR: Alt contains different data than expected" + return 1 + fi +} + +@test "Option 'yadm.cygwin-copy' (unset, non-cygwin)" { + echo " + When the option 'yadm.cygwin-copy' is unset + and the OS is not CYGWIN + Verify alternate is a symlink + " + test_alt 'unset' 'false' 'true' +} + +@test "Option 'yadm.cygwin-copy' (true, non-cygwin)" { + echo " + When the option 'yadm.cygwin-copy' is true + and the OS is not CYGWIN + Verify alternate is a symlink + " + test_alt 'true' 'false' 'true' +} + +@test "Option 'yadm.cygwin-copy' (false, non-cygwin)" { + echo " + When the option 'yadm.cygwin-copy' is false + and the OS is not CYGWIN + Verify alternate is a symlink + " + test_alt 'false' 'false' 'true' +} + +@test "Option 'yadm.cygwin-copy' (unset, cygwin)" { + echo " + When the option 'yadm.cygwin-copy' is unset + and the OS is CYGWIN + Verify alternate is a symlink + " + test_alt 'unset' 'true' 'true' +} + +@test "Option 'yadm.cygwin-copy' (true, cygwin)" { + echo " + When the option 'yadm.cygwin-copy' is true + and the OS is CYGWIN + Verify alternate is a copy + " + test_alt 'true' 'true' 'false' +} + +@test "Option 'yadm.cygwin-copy' (false, cygwin)" { + echo " + When the option 'yadm.cygwin-copy' is false + and the OS is CYGWIN + Verify alternate is a symlink + " + test_alt 'false' 'true' 'true' +} diff --git a/test/common.bash b/test/common.bash index 5670ed0..d617db1 100644 --- a/test/common.bash +++ b/test/common.bash @@ -205,6 +205,18 @@ function create_worktree() { echo "{{ YADM_CLASS }}-{{ YADM_OS }}-{{ YADM_HOSTNAME }}-{{ YADM_USER }}" > "$DIR_WORKTREE/alt-jinja##yadm.j2" fi + #; for some cygwin tests + if [ ! -z "$TEST_TREE_WITH_CYGWIN" ] ; then + for f in \ + "alt-test##" \ + "alt-test##$T_SYS" \ + "alt-test##$SIMULATED_CYGWIN" \ + ; + do + make_parents "$DIR_WORKTREE/$f" + echo "$f" > "$DIR_WORKTREE/$f" + done + fi if [ ! -z "$TEST_TREE_WITH_WILD" ] ; then #; wildcard test data - yes this is a big mess :( diff --git a/yadm b/yadm index 5787d65..ada5cab 100755 --- a/yadm +++ b/yadm @@ -175,6 +175,14 @@ function alt() { done < "$YADM_ENCRYPT" fi + #; decide if a copy should be done instead of a symbolic link + local do_copy=0 + if [[ $OPERATING_SYSTEM == CYGWIN* ]] ; then + if [[ $(config --bool yadm.cygwin-copy) == "true" ]] ; then + do_copy=1 + fi + fi + #; loop over all "tracked" files #; for every file which matches the above regex, create a symlink for match in $match1 $match2; do @@ -190,7 +198,11 @@ function alt() { new_link="${BASH_REMATCH[1]}" debug "Linking $alt_path to $new_link" [ -n "$loud" ] && echo "Linking $alt_path to $new_link" - ln -nfs "$alt_path" "$new_link" + if [ "$do_copy" -eq 1 ]; then + cp -f "$alt_path" "$new_link" + else + ln -nfs "$alt_path" "$new_link" + fi last_linked="$alt_path" fi fi @@ -586,6 +598,7 @@ local.os local.user yadm.auto-alt yadm.auto-perms +yadm.cygwin-copy yadm.git-program yadm.gpg-perms yadm.gpg-program diff --git a/yadm.1 b/yadm.1 index a24aa9a..ce31b12 100644 --- a/yadm.1 +++ b/yadm.1 @@ -376,6 +376,11 @@ By default, the first "gpg" found in $PATH is used. .B yadm.git-program Specify an alternate program to use instead of "git". By default, the first "git" found in $PATH is used. +.TP +.B yadm.cygwin-copy +If set to "true", for Cygwin hosts, alternate files will be copies instead of +symbolic links. This might be desirable, because non-Cygwin software may not +properly interpret Cygwin symlinks. .RE These last four "local" configurations are not stored in the From 7538851fe37388dbc65cea174b000ac33f6c7907 Mon Sep 17 00:00:00 2001 From: Tim Byrne Date: Thu, 1 Jun 2017 07:58:23 -0500 Subject: [PATCH 05/20] Gracefully handle changes in yadm.cygwin-copy --- test/116_accept_cygwin_copy.bats | 29 +++++++++++++++++++++++++++++ yadm | 3 +++ 2 files changed, 32 insertions(+) diff --git a/test/116_accept_cygwin_copy.bats b/test/116_accept_cygwin_copy.bats index 07957c9..8d1ff04 100644 --- a/test/116_accept_cygwin_copy.bats +++ b/test/116_accept_cygwin_copy.bats @@ -1,5 +1,6 @@ load common load_fixtures +status=;output=; #; populated by bats run() IN_REPO=(alt*) export TEST_TREE_WITH_CYGWIN=1 @@ -14,6 +15,7 @@ test_alt() { local cygwin_copy="$1" local is_cygwin="$2" local expect_link="$3" + local preexisting_link="$4" case "$cygwin_copy" in true|false) @@ -30,8 +32,17 @@ test_alt() { local expected_content expected_content="$T_DIR_WORK/alt-test##$(PATH="$T_TMP:$PATH" uname -s)" + if [ "$preexisting_link" = 'symlink' ]; then + ln -s "$expected_content" "$T_DIR_WORK/alt-test" + elif [ "$preexisting_link" = 'file' ]; then + touch "$T_DIR_WORK/alt-test" + fi + PATH="$T_TMP:$PATH" run "${T_YADM_Y[@]}" alt + echo "Alt output:$output" + echo "Alt status:$status" + if [ -L "$T_DIR_WORK/alt-test" ] && [ "$expect_link" != 'true' ] ; then echo "ERROR: Alt should be a simple file, but isn't" return 1 @@ -100,3 +111,21 @@ test_alt() { " test_alt 'false' 'true' 'true' } + +@test "Option 'yadm.cygwin-copy' (preexisting symlink) " { + echo " + When the option 'yadm.cygwin-copy' is true + and the OS is CYGWIN + Verify alternate is a copy + " + test_alt 'true' 'true' 'false' 'symlink' +} + +@test "Option 'yadm.cygwin-copy' (preexisting file) " { + echo " + When the option 'yadm.cygwin-copy' is true + and the OS is CYGWIN + Verify alternate is a copy + " + test_alt 'true' 'true' 'false' 'file' +} diff --git a/yadm b/yadm index ada5cab..878248e 100755 --- a/yadm +++ b/yadm @@ -199,6 +199,9 @@ function alt() { debug "Linking $alt_path to $new_link" [ -n "$loud" ] && echo "Linking $alt_path to $new_link" if [ "$do_copy" -eq 1 ]; then + if [ -L "$new_link" ]; then + rm -f "$new_link" + fi cp -f "$alt_path" "$new_link" else ln -nfs "$alt_path" "$new_link" From 41409631a14b05953af7b407ef59aaa51d7e3cd8 Mon Sep 17 00:00:00 2001 From: Cameron Eagans Date: Thu, 22 Jun 2017 17:32:16 -0600 Subject: [PATCH 06/20] Add script hooks --- yadm | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/yadm b/yadm index 5787d65..21cb1ab 100755 --- a/yadm +++ b/yadm @@ -96,10 +96,14 @@ function main() { shift done [ ! -d "$YADM_WORK" ] && error_out "Work tree does not exist: [$YADM_WORK]" + invoke_hook "pre_$YADM_COMMAND" $YADM_COMMAND "${YADM_ARGS[@]}" + invoke_hook "post_$YADM_COMMAND" else #; any other commands are simply passed through to git + invoke_hook "pre_$1" git_command "$@" + invoke_hook "post_$1" retval="$?" fi @@ -827,6 +831,16 @@ function error_out() { } +#: ****** Hook handler ******S +function invoke_hook() { + hook_name=$1 + + if [[ -x "$YADM_DIR/hooks/$hook_name.sh" ]] ; then + debug "invoking hook: $hook_name" + $YADM_DIR/hooks/$hook_name.sh + fi +} + #; ****** Auto Functions ****** function auto_alt() { From 8d1151a609dae0174c1969fb39e40032190d1533 Mon Sep 17 00:00:00 2001 From: Cameron Eagans Date: Thu, 22 Jun 2017 17:32:31 -0600 Subject: [PATCH 07/20] Document hooks --- yadm.1 | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/yadm.1 b/yadm.1 index a24aa9a..4a13426 100644 --- a/yadm.1 +++ b/yadm.1 @@ -395,6 +395,21 @@ Override the HOSTNAME for the purpose of symlinking alternate files. .TP .B local.user Override the USER for the purpose of symlinking alternate files. +.SH HOOKS +.B yadm +has the capability to execute scripts before or after any operation that +.B yadm +can perform. To utilize this functionality, create a directory to store the hook +scripts at +.BR $HOME/.yadm/hooks. +Then, create scripts inside this directory for whatever operation you want to +hook into. For instance, if you'd like a script to run after +.B yadm pull, +your hook script should be executable and located at +.BR $HOME/.yadm/hooks/post_pull.sh. +Any of the +.B yadm +subcommands can utilize this functionality. .SH ALTERNATES When managing a set of files across different systems, it can be useful to have an automated way of choosing an alternate version of a file for a different From 8ff804c1a9c15510b4372a047768aa618c90e141 Mon Sep 17 00:00:00 2001 From: Cameron Eagans Date: Thu, 22 Jun 2017 17:32:39 -0600 Subject: [PATCH 08/20] Regenerate yadm.md --- yadm.md | 86 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/yadm.md b/yadm.md index aca8c7d..7876133 100644 --- a/yadm.md +++ b/yadm.md @@ -257,12 +257,22 @@ local.user Override the USER for the purpose of symlinking alternate files. +## HOOKS + yadm has the capability to execute scripts before or after any opera- + tion that yadm can perform. To utilize this functionality, create a + directory to store the hook scripts at $HOME/.yadm/hooks. Then, create + scripts inside this directory for whatever operation you want to hook + into. For instance, if you'd like a script to run after yadm pull, your + hook script should be executable and located at + $HOME/.yadm/hooks/post_pull.sh. Any of the yadm subcommands can uti- + lize this functionality. + ## ALTERNATES When managing a set of files across different systems, it can be useful to have an automated way of choosing an alternate version of a file for a different operating system, host, or user. yadm implements a feature which will automatically create a symbolic link to the appropriate ver- - sion of a file, as long as you follow a specific naming convention. + sion of a file, as long as you follow a specific naming convention. yadm can detect files with names ending in any of the following: ## @@ -274,10 +284,10 @@ ##OS.HOSTNAME ##OS.HOSTNAME.USER - If there are any files managed by yadm's repository, or listed in + If there are any files managed by yadm's repository, or listed in $HOME/.yadm/encrypt, which match this naming convention, symbolic links - will be created for the most appropriate version. This may best be - demonstrated by example. Assume the following files are managed by + will be created for the most appropriate version. This may best be + demonstrated by example. Assume the following files are managed by yadm's repository: - $HOME/path/example.txt## @@ -299,7 +309,7 @@ $HOME/path/example.txt -> $HOME/path/example.txt##Darwin - Since the hostname doesn't match any of the managed files, the more + Since the hostname doesn't match any of the managed files, the more generic version is chosen. If running on a Linux server named "host4", the link will be: @@ -317,42 +327,42 @@ If no "##" version exists and no files match the current CLASS/OS/HOST- NAME/USER, then no link will be created. - Links are also created for directories named this way, as long as they + Links are also created for directories named this way, as long as they have at least one yadm managed file within them. - CLASS must be manually set using yadm config local.class . OS - is determined by running uname -s, HOSTNAME by running hostname, and - USER by running id -u -n. yadm will automatically create these links + CLASS must be manually set using yadm config local.class . OS + is determined by running uname -s, HOSTNAME by running hostname, and + USER by running id -u -n. yadm will automatically create these links by default. This can be disabled using the yadm.auto-alt configuration. Even if disabled, links can be manually created by running yadm alt. - It is possible to use "%" as a "wildcard" in place of CLASS, OS, HOST- - NAME, or USER. For example, The following file could be linked for any + It is possible to use "%" as a "wildcard" in place of CLASS, OS, HOST- + NAME, or USER. For example, The following file could be linked for any host when the user is "harvey". $HOME/path/example.txt##%.%.harvey - CLASS is a special value which is stored locally on each host (inside - the local repository). To use alternate symlinks using CLASS, you must - set the value of class using the configuration local.class. This is + CLASS is a special value which is stored locally on each host (inside + the local repository). To use alternate symlinks using CLASS, you must + set the value of class using the configuration local.class. This is set like any other yadm configuration with the yadm config command. The following sets the CLASS to be "Work". yadm config local.class Work - Similarly, the values of OS, HOSTNAME, and USER can be manually over- - ridden using the configuration options local.os, local.hostname, and + Similarly, the values of OS, HOSTNAME, and USER can be manually over- + ridden using the configuration options local.os, local.hostname, and local.user. ## JINJA - If the envtpl command is available, Jinja templates will also be pro- + If the envtpl command is available, Jinja templates will also be pro- cessed to create or overwrite real files. yadm will treat files ending in ##yadm.j2 - as Jinja templates. During processing, the following variables are set + as Jinja templates. During processing, the following variables are set according to the rules explained in the ALTERNATES section: YADM_CLASS @@ -368,7 +378,7 @@ config=dev-whatever {% endif -%} - would output a file named whatever with the following content if the + would output a file named whatever with the following content if the user is "harvey": config=work-Linux @@ -381,44 +391,44 @@ ## ENCRYPTION - It can be useful to manage confidential files, like SSH or GPG keys, - across multiple systems. However, doing so would put plain text data - into a Git repository, which often resides on a public system. yadm - implements a feature which can make it easy to encrypt and decrypt a - set of files so the encrypted version can be maintained in the Git - repository. This feature will only work if the gpg(1) command is + It can be useful to manage confidential files, like SSH or GPG keys, + across multiple systems. However, doing so would put plain text data + into a Git repository, which often resides on a public system. yadm + implements a feature which can make it easy to encrypt and decrypt a + set of files so the encrypted version can be maintained in the Git + repository. This feature will only work if the gpg(1) command is available. - To use this feature, a list of patterns must be created and saved as - $HOME/.yadm/encrypt. This list of patterns should be relative to the + To use this feature, a list of patterns must be created and saved as + $HOME/.yadm/encrypt. This list of patterns should be relative to the configured work-tree (usually $HOME). For example: .ssh/*.key .gnupg/*.gpg The yadm encrypt command will find all files matching the patterns, and - prompt for a password. Once a password has confirmed, the matching - files will be encrypted and saved as $HOME/.yadm/files.gpg. The pat- - terns and files.gpg should be added to the yadm repository so they are + prompt for a password. Once a password has confirmed, the matching + files will be encrypted and saved as $HOME/.yadm/files.gpg. The pat- + terns and files.gpg should be added to the yadm repository so they are available across multiple systems. To decrypt these files later, or on another system run yadm decrypt and - provide the correct password. After files are decrypted, permissions + provide the correct password. After files are decrypted, permissions are automatically updated as described in the PERMISSIONS section. - Symmetric encryption is used by default, but asymmetric encryption may + Symmetric encryption is used by default, but asymmetric encryption may be enabled using the yadm.gpg-recipient configuration. - NOTE: It is recommended that you use a private repository when keeping + NOTE: It is recommended that you use a private repository when keeping confidential files, even though they are encrypted. ## PERMISSIONS - When files are checked out of a Git repository, their initial permis- + When files are checked out of a Git repository, their initial permis- sions are dependent upon the user's umask. This can result in confiden- tial files with lax permissions. To prevent this, yadm will automatically update the permissions of con- - fidential files. The "group" and "others" permissions will be removed + fidential files. The "group" and "others" permissions will be removed from the following files: - $HOME/.yadm/files.gpg @@ -430,13 +440,13 @@ - The GPG directory and files, .gnupg/* yadm will automatically update permissions by default. This can be dis- - abled using the yadm.auto-perms configuration. Even if disabled, per- + abled using the yadm.auto-perms configuration. Even if disabled, per- missions can be manually updated by running yadm perms. The SSH direc- tory processing can be disabled using the yadm.ssh-perms configuration. ## FILES - The following are the default paths yadm uses for its own data. These - paths can be altered using universal options. See the OPTIONS section + The following are the default paths yadm uses for its own data. These + paths can be altered using universal options. See the OPTIONS section for details. $HOME/.yadm From cf06ca3f42adf62c3638a194c5ea8c890189f365 Mon Sep 17 00:00:00 2001 From: Cameron Eagans Date: Thu, 22 Jun 2017 17:32:47 -0600 Subject: [PATCH 09/20] Add myself as a contributor --- CONTRIBUTORS | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index b7094cd..ee19531 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -12,3 +12,4 @@ Tomas Cernaj Uroš Golja Franciszek Madej Klas Mellbourn +Cameron Eagans From 280b1179f753ff2485ccf2250bc9e8dd670fca77 Mon Sep 17 00:00:00 2001 From: Tim Byrne Date: Mon, 3 Jul 2017 16:21:06 -0500 Subject: [PATCH 10/20] Add `lsb-release` to testbed (to support YADM_DISTRO) --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index d0ec689..74700c4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM ubuntu:yakkety MAINTAINER Tim Byrne # Install prerequisites -RUN apt-get update && apt-get install -y git gnupg1 make shellcheck bats expect curl python-pip +RUN apt-get update && apt-get install -y git gnupg1 make shellcheck bats expect curl python-pip lsb-release RUN pip install envtpl # Force GNUPG version 1 at path /usr/bin/gpg From 5293db986ad26cac92ad021c88c9aa213f5648ea Mon Sep 17 00:00:00 2001 From: Tim Byrne Date: Mon, 3 Jul 2017 16:21:27 -0500 Subject: [PATCH 11/20] Support `YADM_DISTRO` in Jinja templates (#68) --- test/007_unit_query_distro.bats | 49 +++++++++++++++++++++++++++++++++ test/113_accept_jinja_alt.bats | 4 +-- test/common.bash | 4 ++- yadm | 10 +++++++ 4 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 test/007_unit_query_distro.bats diff --git a/test/007_unit_query_distro.bats b/test/007_unit_query_distro.bats new file mode 100644 index 0000000..639ab29 --- /dev/null +++ b/test/007_unit_query_distro.bats @@ -0,0 +1,49 @@ +load common +load_fixtures + +@test "Query distro (lsb_release present)" { + echo " + Use value of lsb_release -si + " + + #shellcheck source=/dev/null + YADM_TEST=1 source "$T_YADM" + status=0 + { output=$( query_distro ); } || { + status=$? + true + } + + expected="${T_DISTRO}" + + echo "output=$output" + echo "expect=$expected" + + [ "$status" == 0 ] + [ "$output" = "$expected" ] +} + +@test "Query distro (lsb_release missing)" { + echo " + Empty value if lsb_release is missing + " + + #shellcheck source=/dev/null + YADM_TEST=1 source "$T_YADM" + LSB_RELEASE_PROGRAM="missing_lsb_release" + echo "Using $LSB_RELEASE_PROGRAM as lsb_release" + + status=0 + { output=$( query_distro ); } || { + status=$? + true + } + + expected="" + + echo "output=$output" + echo "expect=$expected" + + [ "$status" == 0 ] + [ "$output" = "$expected" ] +} diff --git a/test/113_accept_jinja_alt.bats b/test/113_accept_jinja_alt.bats index 6ed6c63..8cfe343 100644 --- a/test/113_accept_jinja_alt.bats +++ b/test/113_accept_jinja_alt.bats @@ -21,11 +21,11 @@ function test_alt() { case $alt_type in base) real_name="alt-jinja" - file_content_match="-${T_SYS}-${T_HOST}-${T_USER}" + file_content_match="-${T_SYS}-${T_HOST}-${T_USER}-${T_DISTRO}" ;; override_all) real_name="alt-jinja" - file_content_match="custom_class-custom_system-custom_host-custom_user" + file_content_match="custom_class-custom_system-custom_host-custom_user-${T_DISTRO}" ;; esac diff --git a/test/common.bash b/test/common.bash index d617db1..46a38b1 100644 --- a/test/common.bash +++ b/test/common.bash @@ -27,6 +27,8 @@ function load_fixtures() { T_HOST=$(hostname -s) export T_USER T_USER=$(id -u -n) + export T_DISTRO + T_DISTRO=$(lsb_release -si 2>/dev/null || true) } function configure_git() { @@ -202,7 +204,7 @@ function create_worktree() { make_parents "$DIR_WORKTREE/$f" echo "$f" > "$DIR_WORKTREE/$f" done - echo "{{ YADM_CLASS }}-{{ YADM_OS }}-{{ YADM_HOSTNAME }}-{{ YADM_USER }}" > "$DIR_WORKTREE/alt-jinja##yadm.j2" + echo "{{ YADM_CLASS }}-{{ YADM_OS }}-{{ YADM_HOSTNAME }}-{{ YADM_USER }}-{{ YADM_DISTRO }}" > "$DIR_WORKTREE/alt-jinja##yadm.j2" fi #; for some cygwin tests diff --git a/yadm b/yadm index 878248e..9938169 100755 --- a/yadm +++ b/yadm @@ -34,6 +34,7 @@ GPG_PROGRAM="gpg" GIT_PROGRAM="git" LS_PROGRAM="/bin/ls" ENVTPL_PROGRAM="envtpl" +LSB_RELEASE_PROGRAM="lsb_release" PROC_VERSION="/proc/version" OPERATING_SYSTEM="Unknown" @@ -230,6 +231,7 @@ function alt() { YADM_OS="$local_system" \ YADM_HOSTNAME="$local_host" \ YADM_USER="$local_user" \ + YADM_DISTRO=$(query_distro) \ "$ENVTPL_PROGRAM" < "$tracked_file" > "$real_file" else debug "envtpl not available, not creating $real_file from template $tracked_file" @@ -698,6 +700,14 @@ function version() { #; ****** Utility Functions ****** +function query_distro() { + distro="" + if command -v "$LSB_RELEASE_PROGRAM" >/dev/null 2>&1; then + distro=$($LSB_RELEASE_PROGRAM -si 2>/dev/null) + fi + echo "$distro" +} + function process_global_args() { #; global arguments are removed before the main processing is done From 880964e2b2cd42c304f39da8190622cd749cfc06 Mon Sep 17 00:00:00 2001 From: Tim Byrne Date: Mon, 3 Jul 2017 16:25:03 -0500 Subject: [PATCH 12/20] Some initial tweaks to hooks * No not require `.sh` extension. Hooks can be written in any language. * Use `[` for the `-x` test * Clean up debug message and formatting --- yadm | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/yadm b/yadm index ab06720..ea98655 100755 --- a/yadm +++ b/yadm @@ -857,14 +857,15 @@ function error_out() { } -#: ****** Hook handler ******S function invoke_hook() { - hook_name=$1 - if [[ -x "$YADM_DIR/hooks/$hook_name.sh" ]] ; then - debug "invoking hook: $hook_name" - $YADM_DIR/hooks/$hook_name.sh + hook_name="$1" + + if [ -x "$YADM_DIR/hooks/$hook_name" ] ; then + debug "Invoking hook: $hook_name" + "$YADM_DIR/hooks/$hook_name" fi + } #; ****** Auto Functions ****** From 35743e3711e5db60f3ab71e7fd3feeb8378abb4d Mon Sep 17 00:00:00 2001 From: Tim Byrne Date: Mon, 3 Jul 2017 16:25:23 -0500 Subject: [PATCH 13/20] Tie "post" hooks to yadm exits There are many cases where yadm may exit early (particularly when encountering an error). --- yadm | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/yadm b/yadm index ea98655..57eb5bb 100755 --- a/yadm +++ b/yadm @@ -30,6 +30,8 @@ YADM_ENCRYPT="encrypt" YADM_ARCHIVE="files.gpg" YADM_BOOTSTRAP="bootstrap" +HOOK_COMMAND="" + GPG_PROGRAM="gpg" GIT_PROGRAM="git" LS_PROGRAM="/bin/ls" @@ -97,14 +99,14 @@ function main() { shift done [ ! -d "$YADM_WORK" ] && error_out "Work tree does not exist: [$YADM_WORK]" - invoke_hook "pre_$YADM_COMMAND" + HOOK_COMMAND="$YADM_COMMAND" + invoke_hook "pre" $YADM_COMMAND "${YADM_ARGS[@]}" - invoke_hook "post_$YADM_COMMAND" else #; any other commands are simply passed through to git - invoke_hook "pre_$1" + HOOK_COMMAND="$1" + invoke_hook "pre" git_command "$@" - invoke_hook "post_$1" retval="$?" fi @@ -113,7 +115,7 @@ function main() { auto_perms auto_bootstrap - exit $retval + exit_with_hook $retval } @@ -546,7 +548,7 @@ Files: Use "man yadm" for complete documentation. EOF - exit 1 + exit_with_hook 1 } @@ -698,7 +700,7 @@ function perms() { function version() { echo "yadm $VERSION" - exit 0 + exit_with_hook 0 } @@ -853,17 +855,25 @@ function debug() { function error_out() { echo -e "ERROR: $*" - exit 1 + exit_with_hook 1 + +} + +function exit_with_hook() { + + invoke_hook "post" + exit "$1" } function invoke_hook() { - hook_name="$1" + mode="$1" + hook_command="$YADM_DIR/hooks/${mode}_$HOOK_COMMAND" - if [ -x "$YADM_DIR/hooks/$hook_name" ] ; then - debug "Invoking hook: $hook_name" - "$YADM_DIR/hooks/$hook_name" + if [ -x "$hook_command" ] ; then + debug "Invoking hook: $hook_command" + "$hook_command" fi } From f73c873681a7daf3c9f70e0c216b5b3b76ba40ad Mon Sep 17 00:00:00 2001 From: Tim Byrne Date: Wed, 5 Jul 2017 07:58:40 -0500 Subject: [PATCH 14/20] Expose some internal data to all hooks * Command run by yadm * Full commandline arguments * Repo directory * Worktree * Exit status (for post hooks) --- yadm | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/yadm b/yadm index 57eb5bb..a547142 100755 --- a/yadm +++ b/yadm @@ -31,6 +31,7 @@ YADM_ARCHIVE="files.gpg" YADM_BOOTSTRAP="bootstrap" HOOK_COMMAND="" +FULL_COMMAND="" GPG_PROGRAM="gpg" GIT_PROGRAM="git" @@ -55,6 +56,9 @@ function main() { require_git + #; capture full command, for passing to hooks + FULL_COMMAND="$*" + #; create the YADM_DIR if it doesn't exist yet [ -d "$YADM_DIR" ] || mkdir -p "$YADM_DIR" @@ -861,7 +865,7 @@ function error_out() { function exit_with_hook() { - invoke_hook "post" + invoke_hook "post" "$1" exit "$1" } @@ -869,10 +873,24 @@ function exit_with_hook() { function invoke_hook() { mode="$1" + exit_status="$2" hook_command="$YADM_DIR/hooks/${mode}_$HOOK_COMMAND" if [ -x "$hook_command" ] ; then debug "Invoking hook: $hook_command" + + #; expose some internal data to all hooks + YADM_HOOK_COMMAND=$HOOK_COMMAND + YADM_HOOK_EXIT=$exit_status + YADM_HOOK_FULL_COMMAND=$FULL_COMMAND + YADM_HOOK_REPO=$YADM_REPO + YADM_HOOK_WORK=$YADM_WORK + export YADM_HOOK_COMMAND + export YADM_HOOK_EXIT + export YADM_HOOK_FULL_COMMAND + export YADM_HOOK_REPO + export YADM_HOOK_WORK + "$hook_command" fi From 61270c827788c68f22b26f437e0adafcbe4b2c3d Mon Sep 17 00:00:00 2001 From: Tim Byrne Date: Wed, 5 Jul 2017 08:11:50 -0500 Subject: [PATCH 15/20] Prevent command from running if "pre" hook fails --- yadm | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/yadm b/yadm index a547142..93252fb 100755 --- a/yadm +++ b/yadm @@ -892,6 +892,15 @@ function invoke_hook() { export YADM_HOOK_WORK "$hook_command" + hook_status=$? + + #; failing "pre" hooks will prevent commands from being run + if [ "$mode" = "pre" ] && [ "$hook_status" -ne 0 ]; then + echo "Hook $hook_command was not successful" + echo "$HOOK_COMMAND will not be run" + exit "$hook_status" + fi + fi } From 0168bcfb5e3dfa086900cac098da06cc375a6399 Mon Sep 17 00:00:00 2001 From: Tim Byrne Date: Wed, 5 Jul 2017 16:21:54 -0500 Subject: [PATCH 16/20] Query worktree directly from repo --- yadm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yadm b/yadm index 93252fb..9429172 100755 --- a/yadm +++ b/yadm @@ -880,11 +880,12 @@ function invoke_hook() { debug "Invoking hook: $hook_command" #; expose some internal data to all hooks + work=$(unix_path "$("$GIT_PROGRAM" config core.worktree)") YADM_HOOK_COMMAND=$HOOK_COMMAND YADM_HOOK_EXIT=$exit_status YADM_HOOK_FULL_COMMAND=$FULL_COMMAND YADM_HOOK_REPO=$YADM_REPO - YADM_HOOK_WORK=$YADM_WORK + YADM_HOOK_WORK=$work export YADM_HOOK_COMMAND export YADM_HOOK_EXIT export YADM_HOOK_FULL_COMMAND From 557ce93fab5adc28f6218ec1e45d6245617a4c4c Mon Sep 17 00:00:00 2001 From: Tim Byrne Date: Wed, 5 Jul 2017 16:32:10 -0500 Subject: [PATCH 17/20] Add tests for hooks --- test/117_accept_hooks.bats | 181 +++++++++++++++++++++++++++++++++++++ test/common.bash | 1 + 2 files changed, 182 insertions(+) create mode 100644 test/117_accept_hooks.bats diff --git a/test/117_accept_hooks.bats b/test/117_accept_hooks.bats new file mode 100644 index 0000000..5e8f348 --- /dev/null +++ b/test/117_accept_hooks.bats @@ -0,0 +1,181 @@ +load common +load_fixtures +status=;output=; #; populated by bats run() + +version_regex="yadm [[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+" + +setup() { + destroy_tmp + build_repo + mkdir -p "$T_DIR_HOOKS" +} + +function create_hook() { + hook_name="$1" + hook_exit="$2" + hook_file="$T_DIR_HOOKS/$hook_name" + { + echo "#!/bin/sh" + echo "echo ran $hook_name" + echo "env" + echo "exit $hook_exit" + } > "$hook_file" + chmod a+x "$hook_file" +} + +@test "Hooks (no hook)" { + echo " + When no hook is present + do no not run the hook + run command + Exit with 0 + " + + #; run yadm with no command + run "${T_YADM_Y[@]}" version + + [ $status -eq 0 ] + [[ "$output" =~ $version_regex ]] +} + +@test "Hooks (successful pre hook)" { + echo " + When hook is present + run hook + run command + Exit with 0 + " + + create_hook "pre_version" "0" + + #; run yadm with no command + run "${T_YADM_Y[@]}" version + + [ $status -eq 0 ] + [[ "$output" =~ ran\ pre_version ]] + [[ "$output" =~ $version_regex ]] +} + +@test "Hooks (unsuccessful pre hook)" { + echo " + When hook is present + run hook + report hook failure + do no not run command + Exit with 13 + " + + create_hook "pre_version" "13" + + #; run yadm with no command + run "${T_YADM_Y[@]}" version + + [ $status -eq 13 ] + [[ "$output" =~ ran\ pre_version ]] + [[ "$output" =~ pre_version\ was\ not\ successful ]] + [[ ! "$output" =~ $version_regex ]] +} + +@test "Hooks (successful post hook)" { + echo " + When hook is present + run command + run hook + Exit with 0 + " + + create_hook "post_version" "0" + + #; run yadm with no command + run "${T_YADM_Y[@]}" version + + [ $status -eq 0 ] + [[ "$output" =~ $version_regex ]] + [[ "$output" =~ ran\ post_version ]] +} + +@test "Hooks (unsuccessful post hook)" { + echo " + When hook is present + run command + run hook + Exit with 0 + " + + create_hook "post_version" "13" + + #; run yadm with no command + run "${T_YADM_Y[@]}" version + + [ $status -eq 0 ] + [[ "$output" =~ $version_regex ]] + [[ "$output" =~ ran\ post_version ]] +} + +@test "Hooks (successful pre hook + post hook)" { + echo " + When hook is present + run hook + run command + run hook + Exit with 0 + " + + create_hook "pre_version" "0" + create_hook "post_version" "0" + + #; run yadm with no command + run "${T_YADM_Y[@]}" version + + [ $status -eq 0 ] + [[ "$output" =~ ran\ pre_version ]] + [[ "$output" =~ $version_regex ]] + [[ "$output" =~ ran\ post_version ]] +} + +@test "Hooks (unsuccessful pre hook + post hook)" { + echo " + When hook is present + run hook + report hook failure + do no not run command + do no not run post hook + Exit with 13 + " + + create_hook "pre_version" "13" + create_hook "post_version" "0" + + #; run yadm with no command + run "${T_YADM_Y[@]}" version + + [ $status -eq 13 ] + [[ "$output" =~ ran\ pre_version ]] + [[ "$output" =~ pre_version\ was\ not\ successful ]] + [[ ! "$output" =~ $version_regex ]] + [[ ! "$output" =~ ran\ post_version ]] +} + +@test "Hooks (environment variables)" { + echo " + When hook is present + run command + run hook + hook should have access to environment variables + Exit with 0 + " + + create_hook "post_version" "0" + + #; run yadm with no command + run "${T_YADM_Y[@]}" version extra_args + + [ $status -eq 0 ] + [[ "$output" =~ $version_regex ]] + [[ "$output" =~ ran\ post_version ]] + [[ "$output" =~ YADM_HOOK_COMMAND=version ]] + [[ "$output" =~ YADM_HOOK_EXIT=0 ]] + [[ "$output" =~ YADM_HOOK_FULL_COMMAND=version\ extra_args ]] + [[ "$output" =~ YADM_HOOK_REPO=${T_DIR_REPO} ]] + [[ "$output" =~ YADM_HOOK_WORK=${T_DIR_WORK} ]] +} diff --git a/test/common.bash b/test/common.bash index 46a38b1..32ba8e1 100644 --- a/test/common.bash +++ b/test/common.bash @@ -13,6 +13,7 @@ function load_fixtures() { export T_DIR_YADM="$T_TMP/.yadm" export T_DIR_WORK="$T_TMP/yadm-work" export T_DIR_REPO="$T_DIR_YADM/repo.git" + export T_DIR_HOOKS="$T_DIR_YADM/hooks" export T_YADM_CONFIG="$T_DIR_YADM/config" export T_YADM_ENCRYPT="$T_DIR_YADM/encrypt" export T_YADM_ARCHIVE="$T_DIR_YADM/files.gpg" From bf61ad662d8ef228f2eadd41d993de33eae3bf2a Mon Sep 17 00:00:00 2001 From: Tim Byrne Date: Thu, 6 Jul 2017 21:53:23 -0500 Subject: [PATCH 18/20] Add new detail to HOOKS documentation --- yadm.1 | 71 +++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 15 deletions(-) diff --git a/yadm.1 b/yadm.1 index 488bb55..fd311f3 100644 --- a/yadm.1 +++ b/yadm.1 @@ -400,21 +400,6 @@ Override the HOSTNAME for the purpose of symlinking alternate files. .TP .B local.user Override the USER for the purpose of symlinking alternate files. -.SH HOOKS -.B yadm -has the capability to execute scripts before or after any operation that -.B yadm -can perform. To utilize this functionality, create a directory to store the hook -scripts at -.BR $HOME/.yadm/hooks. -Then, create scripts inside this directory for whatever operation you want to -hook into. For instance, if you'd like a script to run after -.B yadm pull, -your hook script should be executable and located at -.BR $HOME/.yadm/hooks/post_pull.sh. -Any of the -.B yadm -subcommands can utilize this functionality. .SH ALTERNATES When managing a set of files across different systems, it can be useful to have an automated way of choosing an alternate version of a file for a different @@ -644,6 +629,62 @@ Even if disabled, permissions can be manually updated by running The SSH directory processing can be disabled using the .I yadm.ssh-perms configuration. +.SH HOOKS +For every command +.B yadm +supports, a program can be provided to run before or after that command. These +are referred to as "hooks". +.B yadm +looks for +hooks in the directory +.IR $HOME/.yadm/hooks . +Each hook is named using a prefix of +.I pre_ +or +.IR post_ , +followed by the command which should trigger the hook. For +example, to create a hook which is run after every +.I yadm pull +command, create a hook named +.IR post_pull. +Hooks must have the executable file permission set. + +If a +.I pre_ +hook is defined, and the hook terminates with a non-zero exit status, +.B yadm +will refuse to run the +.B yadm +command. For example, if a +.I pre_commit +hook is defined, but that command ends with a non-zero exit status, the +.I yadm commit +will never be run. This allows one to "short-circuit" any operation using a +.I pre_ +hook. + +Hooks have the following environment variables available to them at runtime: +.TP +.B YADM_HOOK_COMMAND +The command which triggered the hook +.TP +.B YADM_HOOK_EXIT +The exit status of the +.B yadm +command +.TP +.B YADM_HOOK_FULL_COMMAND +The +.B yadm +command with all command line arguments +.TP +.B YADM_HOOK_REPO +The path to the +.B yadm +repository +.TP +.B YADM_HOOK_WORK +The path to the work-tree .SH FILES The following are the default paths .B yadm From df1f7493ab575dd000254a532ff186a1937af13f Mon Sep 17 00:00:00 2001 From: Tim Byrne Date: Fri, 7 Jul 2017 08:23:45 -0500 Subject: [PATCH 19/20] Add documentation for `YADM_DISTRO` support in Jinja templates --- yadm.1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/yadm.1 b/yadm.1 index fd311f3..652c843 100644 --- a/yadm.1 +++ b/yadm.1 @@ -531,6 +531,12 @@ according to the rules explained in the ALTERNATES section: YADM_HOSTNAME YADM_USER +In addition YADM_DISTRO is exposed as the value of +.I lsb_release -si +if +.B lsb_release +is locally available. + For example, a file named .I whatever##yadm.j2 with the following content From 4b5b6c44d37b40b8ad732e25fae3e9567510a0ff Mon Sep 17 00:00:00 2001 From: Tim Byrne Date: Sun, 9 Jul 2017 23:07:50 -0500 Subject: [PATCH 20/20] Release 1.11.0 Update version number and update documentation * Option for Cygwin to copy files instead of symlink (#62) * Support `YADM_DISTRO` in Jinja templates (#68) * Support pre/post hooks for every command (#70) --- CHANGES | 5 +++ CONTRIBUTORS | 3 +- yadm | 2 +- yadm.1 | 2 +- yadm.md | 88 ++++++++++++++++++++++++++++++++++++++-------------- yadm.spec | 5 ++- 6 files changed, 78 insertions(+), 27 deletions(-) diff --git a/CHANGES b/CHANGES index e73fe44..c5a08e6 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +1.11.0 + * Option for Cygwin to copy files instead of symlink (#62) + * Support `YADM_DISTRO` in Jinja templates (#68) + * Support pre/post hooks for every command (#70) + 1.10.0 * Fix `COMP_WORDS bad array subscript` bug (#64) * Transition to semantic versioning diff --git a/CONTRIBUTORS b/CONTRIBUTORS index b7094cd..32b93a4 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -2,8 +2,8 @@ CONTRIBUTORS Tim Byrne Espen Henriksen +Cameron Eagans Jan Schulz -Paraplegic Racehorse Patrick Hof Satoshi Ohki Siôn Le Roux @@ -12,3 +12,4 @@ Tomas Cernaj Uroš Golja Franciszek Madej Klas Mellbourn +Paraplegic Racehorse diff --git a/yadm b/yadm index 9429172..1b8608f 100755 --- a/yadm +++ b/yadm @@ -19,7 +19,7 @@ if [ -z "$BASH_VERSION" ]; then [ "$YADM_TEST" != 1 ] && exec bash "$0" "$@" fi -VERSION=1.10.0 +VERSION=1.11.0 YADM_WORK="$HOME" YADM_DIR="$HOME/.yadm" diff --git a/yadm.1 b/yadm.1 index 652c843..ff0e65b 100644 --- a/yadm.1 +++ b/yadm.1 @@ -1,5 +1,5 @@ ." vim: set spell so=8: -.TH yadm 1 "10 May 2017" "1.10.0" +.TH yadm 1 "10 July 2017" "1.11.0" .SH NAME yadm \- Yet Another Dotfiles Manager .SH SYNOPSIS diff --git a/yadm.md b/yadm.md index aca8c7d..63eeb5b 100644 --- a/yadm.md +++ b/yadm.md @@ -239,19 +239,25 @@ Specify an alternate program to use instead of "git". By default, the first "git" found in $PATH is used. - These last four "local" configurations are not stored in the + yadm.cygwin-copy + If set to "true", for Cygwin hosts, alternate files will be + copies instead of symbolic links. This might be desirable, + because non-Cygwin software may not properly interpret Cygwin + symlinks. + + These last four "local" configurations are not stored in the $HOME/.yadm/config, they are stored in the local repository. local.class - Specify a CLASS for the purpose of symlinking alternate files. + Specify a CLASS for the purpose of symlinking alternate files. By default, no CLASS will be matched. local.os Override the OS for the purpose of symlinking alternate files. local.hostname - Override the HOSTNAME for the purpose of symlinking alternate + Override the HOSTNAME for the purpose of symlinking alternate files. local.user @@ -262,7 +268,7 @@ to have an automated way of choosing an alternate version of a file for a different operating system, host, or user. yadm implements a feature which will automatically create a symbolic link to the appropriate ver- - sion of a file, as long as you follow a specific naming convention. + sion of a file, as long as you follow a specific naming convention. yadm can detect files with names ending in any of the following: ## @@ -274,10 +280,10 @@ ##OS.HOSTNAME ##OS.HOSTNAME.USER - If there are any files managed by yadm's repository, or listed in + If there are any files managed by yadm's repository, or listed in $HOME/.yadm/encrypt, which match this naming convention, symbolic links - will be created for the most appropriate version. This may best be - demonstrated by example. Assume the following files are managed by + will be created for the most appropriate version. This may best be + demonstrated by example. Assume the following files are managed by yadm's repository: - $HOME/path/example.txt## @@ -299,7 +305,7 @@ $HOME/path/example.txt -> $HOME/path/example.txt##Darwin - Since the hostname doesn't match any of the managed files, the more + Since the hostname doesn't match any of the managed files, the more generic version is chosen. If running on a Linux server named "host4", the link will be: @@ -317,42 +323,42 @@ If no "##" version exists and no files match the current CLASS/OS/HOST- NAME/USER, then no link will be created. - Links are also created for directories named this way, as long as they + Links are also created for directories named this way, as long as they have at least one yadm managed file within them. - CLASS must be manually set using yadm config local.class . OS - is determined by running uname -s, HOSTNAME by running hostname, and - USER by running id -u -n. yadm will automatically create these links + CLASS must be manually set using yadm config local.class . OS + is determined by running uname -s, HOSTNAME by running hostname, and + USER by running id -u -n. yadm will automatically create these links by default. This can be disabled using the yadm.auto-alt configuration. Even if disabled, links can be manually created by running yadm alt. - It is possible to use "%" as a "wildcard" in place of CLASS, OS, HOST- - NAME, or USER. For example, The following file could be linked for any + It is possible to use "%" as a "wildcard" in place of CLASS, OS, HOST- + NAME, or USER. For example, The following file could be linked for any host when the user is "harvey". $HOME/path/example.txt##%.%.harvey - CLASS is a special value which is stored locally on each host (inside - the local repository). To use alternate symlinks using CLASS, you must - set the value of class using the configuration local.class. This is + CLASS is a special value which is stored locally on each host (inside + the local repository). To use alternate symlinks using CLASS, you must + set the value of class using the configuration local.class. This is set like any other yadm configuration with the yadm config command. The following sets the CLASS to be "Work". yadm config local.class Work - Similarly, the values of OS, HOSTNAME, and USER can be manually over- - ridden using the configuration options local.os, local.hostname, and + Similarly, the values of OS, HOSTNAME, and USER can be manually over- + ridden using the configuration options local.os, local.hostname, and local.user. ## JINJA - If the envtpl command is available, Jinja templates will also be pro- + If the envtpl command is available, Jinja templates will also be pro- cessed to create or overwrite real files. yadm will treat files ending in ##yadm.j2 - as Jinja templates. During processing, the following variables are set + as Jinja templates. During processing, the following variables are set according to the rules explained in the ALTERNATES section: YADM_CLASS @@ -360,6 +366,9 @@ YADM_HOSTNAME YADM_USER + In addition YADM_DISTRO is exposed as the value of lsb_release -si if + lsb_release is locally available. + For example, a file named whatever##yadm.j2 with the following content {% if YADM_USER == 'harvey' -%} @@ -434,9 +443,42 @@ missions can be manually updated by running yadm perms. The SSH direc- tory processing can be disabled using the yadm.ssh-perms configuration. +## HOOKS + For every command yadm supports, a program can be provided to run + before or after that command. These are referred to as "hooks". yadm + looks for hooks in the directory $HOME/.yadm/hooks. Each hook is named + using a prefix of pre_ or post_, followed by the command which should + trigger the hook. For example, to create a hook which is run after + every yadm pull command, create a hook named post_pull. Hooks must + have the executable file permission set. + + If a pre_ hook is defined, and the hook terminates with a non-zero exit + status, yadm will refuse to run the yadm command. For example, if a + pre_commit hook is defined, but that command ends with a non-zero exit + status, the yadm commit will never be run. This allows one to "short- + circuit" any operation using a pre_ hook. + + Hooks have the following environment variables available to them at + runtime: + + YADM_HOOK_COMMAND + The command which triggered the hook + + YADM_HOOK_EXIT + The exit status of the yadm command + + YADM_HOOK_FULL_COMMAND + The yadm command with all command line arguments + + YADM_HOOK_REPO + The path to the yadm repository + + YADM_HOOK_WORK + The path to the work-tree + ## FILES - The following are the default paths yadm uses for its own data. These - paths can be altered using universal options. See the OPTIONS section + The following are the default paths yadm uses for its own data. These + paths can be altered using universal options. See the OPTIONS section for details. $HOME/.yadm diff --git a/yadm.spec b/yadm.spec index 9fd90d0..ae18f39 100644 --- a/yadm.spec +++ b/yadm.spec @@ -1,6 +1,6 @@ Summary: Yet Another Dotfiles Manager Name: yadm -Version: 1.10.0 +Version: 1.11.0 Release: 1%{?dist} URL: https://github.com/TheLocehiliosan/yadm License: GPLv3 @@ -37,6 +37,9 @@ install -m 644 yadm.1 ${RPM_BUILD_ROOT}%{_mandir}/man1 %doc CHANGES CONTRIBUTORS README.md completion/yadm.bash_completion %changelog +* Mon July 10 2017 Tim Byrne - 1.11.0-1 +- Bump version to 1.11.0 + * Wed May 10 2017 Tim Byrne - 1.10.0-1 - Bump version to 1.10.0 - Transition to semantic versioning