1
0
mirror of https://github.com/TheLocehiliosan/yadm synced 2025-06-13 13:03:58 +00:00

Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Chad Homan 2018-01-29 16:28:41 -06:00
commit 130965e34d
22 changed files with 1067 additions and 257 deletions

10
CHANGES
View File

@ -1,3 +1,13 @@
1.12.0
* Add basic Zsh completion (#71, #79)
* Support directories in `.yadm/encrypt` (#81, #82)
* Support exclusions in `.yadm/encrypt` (#86)
* Improve portability with printf (#87)
* Eliminate usage of `eval` and `ls`
1.11.1
* Create private dirs prior to merge (#74)
1.11.0
* Option for Cygwin to copy files instead of symlink (#62)
* Support `YADM_DISTRO` in Jinja templates (#68)

View File

@ -3,13 +3,15 @@ CONTRIBUTORS
Tim Byrne
Espen Henriksen
Cameron Eagans
Klas Mellbourn
Jan Schulz
Patrick Hof
Satoshi Ohki
Siôn Le Roux
Sébastien Gross
Thomas Luzat
Tomas Cernaj
Uroš Golja
japm48
Franciszek Madej
Klas Mellbourn
Paraplegic Racehorse
Patrick Hof
Satoshi Ohki

View File

@ -1,12 +1,15 @@
.PHONY: all
all: yadm.md contrib
yadm.md: yadm.1
@groff -man -Tascii ./yadm.1 | col -bx | sed 's/^[A-Z]/## &/g' | sed '/yadm(1)/d' > yadm.md
.PHONY: contrib
contrib:
@echo "CONTRIBUTORS\n" > CONTRIBUTORS
@git shortlog -ns master gh-pages dev dev-pages | cut -f2 >> CONTRIBUTORS
.PHONY: pdf
pdf:
@groff -man -Tps ./yadm.1 > yadm.ps
@open yadm.ps
@ -39,8 +42,19 @@ shellcheck:
[ "$$test_result" -ne 0 ] && exit 1; \
done; true
.PHONY: testhost
testhost:
@target=HEAD
@rm -rf /tmp/testhost
@git show $(target):yadm > /tmp/testhost
@chmod a+x /tmp/testhost
@echo Starting testhost target=\"$$target\"
@docker run -w /root --hostname testhost --rm -it -v "/tmp/testhost:/bin/yadm:ro" yadm/testbed:latest bash
.PHONY: man
man:
groff -man -Tascii ./yadm.1 | less
.PHONY: wide
wide:
man ./yadm.1

View File

@ -1,19 +1,36 @@
# Prerequisites
**yadm** completion only works if Git completions are also enabled.
# Installation
## Homebrew
## Bash completions
### Prerequisites
**yadm** completion only works if Git completions are also enabled.
### Homebrew
If using `homebrew` to install **yadm**, completions should automatically be handled if you also install `brew install bash-completion`. This might require you to include the main completion script in your own bashrc file like this:
```
[ -f /usr/local/etc/bash_completion ] && source /usr/local/etc/bash_completion
```
## Manual installation
### Manual installation
Copy the completion script locally, and add this to you bashrc:
```
[ -f /full/path/to/yadm.bash_completion ] && source /full/path/to/yadm.bash_completion
```
## Zsh completions
### Homebrew
If using `homebrew` to install **yadm**, completions should handled automatically.
### Manual installation
Copy the completion script `yadm.zsh_completion` locally, rename it to `_yadm`, and add the containing folder to `$fpath` in `.zshrc`:
```
fpath=(/path/to/folder/containing_yadm $fpath)
autoload -U compinit
compinit
```
### Installation using [zplug](https://github.com/b4b4r07/zplug)
Load `_yadm` as a plugin in your `.zshrc`:
```
fpath=("$ZPLUG_HOME/bin" $fpath)
zplug "TheLocehiliosan/yadm", rename-to:_yadm, use:"completion/yadm.zsh_completion", as:command, defer:2
```

View File

@ -0,0 +1,46 @@
#compdef yadm
_yadm(){
local -a _1st_arguments
_1st_arguments=(
'help:Display yadm command help'
'init:Initialize an empty repository'
'config:Configure a setting'
'list:List tracked files'
'alt:Create links for alternates'
'bootstrap:Execute $HOME/.yadm/bootstrap'
'encrypt:Encrypt files'
'decrypt:Decrypt files'
'perms:Fix perms for private files'
'add:git add'
'push:git push'
'pull:git pull'
'diff:git diff'
'checkout:git checkout'
'co:git co'
'commit:git commit'
'ci:git ci'
'status:git status'
'st:git st'
'reset:git reset'
'log:git log'
)
local context state line expl
local -A opt_args
_arguments '*:: :->subcmds' && return 0
if (( CURRENT == 1 )); then
_describe -t commands "yadm commands" _1st_arguments -V1
return
fi
case "$words[1]" in
*)
_arguments ':filenames:_files'
;;
esac
}
_yadm "$@"

View File

@ -1,66 +0,0 @@
load common
load_fixtures
@test "Default /bin/ls" {
echo "
By default, the value of LS_PROGRAM should be /bin/ls
"
# shellcheck source=/dev/null
YADM_TEST=1 source "$T_YADM"
status=0
output=$( require_ls; echo "$LS_PROGRAM" ) || {
status=$?
true
}
echo "output=$output"
[ "$status" == 0 ]
[ "$output" = "/bin/ls" ]
}
@test "Fallback on 'ls'" {
echo "
When LS_PROGRAM doesn't exist, use 'ls'
"
# shellcheck source=/dev/null
YADM_TEST=1 source "$T_YADM"
status=0
LS_PROGRAM="/ls/missing"
output=$( require_ls; echo "$LS_PROGRAM" ) || {
status=$?
true
}
echo "output=$output"
[ "$status" == 0 ]
[ "$output" = "ls" ]
}
@test "Fail if ls isn't in PATH" {
echo "
When LS_PROGRAM doesn't exist, use 'ls'
"
# shellcheck source=/dev/null
YADM_TEST=1 source "$T_YADM"
status=0
LS_PROGRAM="/ls/missing"
savepath="$PATH"
# shellcheck disable=SC2123
PATH=
output=$( require_ls 2>&1; echo "$LS_PROGRAM" ) || {
status=$?
true
}
PATH="$savepath"
echo "output=$output"
[ "$status" != 0 ]
[[ "$output" =~ functionality\ requires\ .ls.\ to\ be\ installed ]]
}

View File

@ -0,0 +1,318 @@
load common
load_fixtures
setup() {
# SC2153 is intentional
# shellcheck disable=SC2153
make_parents "$T_YADM_ENCRYPT"
make_parents "$T_DIR_WORK"
make_parents "$T_DIR_REPO"
mkdir "$T_DIR_WORK"
git init --shared=0600 --bare "$T_DIR_REPO" >/dev/null 2>&1
GIT_DIR="$T_DIR_REPO" git config core.bare 'false'
GIT_DIR="$T_DIR_REPO" git config core.worktree "$T_DIR_WORK"
GIT_DIR="$T_DIR_REPO" git config yadm.managed 'true'
}
teardown() {
destroy_tmp
}
function run_parse() {
# shellcheck source=/dev/null
YADM_TEST=1 source "$T_YADM"
YADM_ENCRYPT="$T_YADM_ENCRYPT"
export YADM_ENCRYPT
GIT_DIR="$T_DIR_REPO"
export GIT_DIR
# shellcheck disable=SC2034
status=0
{ output=$( parse_encrypt) && parse_encrypt; } || {
status=$?
true
}
if [ "$1" == "twice" ]; then
GIT_DIR="$T_DIR_REPO" parse_encrypt
fi
echo -e "OUTPUT:$output\n"
echo "ENCRYPT_INCLUDE_FILES:"
echo " Size: ${#ENCRYPT_INCLUDE_FILES[@]}"
echo " Items: ${ENCRYPT_INCLUDE_FILES[*]}"
echo "EXPECT_INCLUDE:"
echo " Size: ${#EXPECT_INCLUDE[@]}"
echo " Items: ${EXPECT_INCLUDE[*]}"
}
@test "parse_encrypt (not called)" {
echo "
parse_encrypt() is not called
Array should be 'unparsed'
"
# shellcheck source=/dev/null
YADM_TEST=1 source "$T_YADM"
echo "ENCRYPT_INCLUDE_FILES=$ENCRYPT_INCLUDE_FILES"
[ "$ENCRYPT_INCLUDE_FILES" == "unparsed" ]
}
@test "parse_encrypt (short-circuit)" {
echo "
Parsing should not happen more than once
"
run_parse "twice"
echo "PARSE_ENCRYPT_SHORT: $PARSE_ENCRYPT_SHORT"
[ "$status" == 0 ]
[ "$output" == "" ]
[[ "$PARSE_ENCRYPT_SHORT" =~ not\ reprocessed ]]
}
@test "parse_encrypt (file missing)" {
echo "
.yadm/encrypt is empty
Array should be empty
"
EXPECT_INCLUDE=()
run_parse
[ "$status" == 0 ]
[ "$output" == "" ]
[ "${#ENCRYPT_INCLUDE_FILES[@]}" -eq "${#EXPECT_INCLUDE[@]}" ]
[ "${ENCRYPT_INCLUDE_FILES[*]}" == "${EXPECT_INCLUDE[*]}" ]
}
@test "parse_encrypt (empty file)" {
echo "
.yadm/encrypt is empty
Array should be empty
"
touch "$T_YADM_ENCRYPT"
EXPECT_INCLUDE=()
run_parse
[ "$status" == 0 ]
[ "$output" == "" ]
[ "${#ENCRYPT_INCLUDE_FILES[@]}" -eq "${#EXPECT_INCLUDE[@]}" ]
[ "${ENCRYPT_INCLUDE_FILES[*]}" == "${EXPECT_INCLUDE[*]}" ]
}
@test "parse_encrypt (files)" {
echo "
.yadm/encrypt is references present and missing files
Array should be as expected
"
echo "file1" > "$T_DIR_WORK/file1"
echo "file3" > "$T_DIR_WORK/file3"
echo "file5" > "$T_DIR_WORK/file5"
{ echo "file1"
echo "file2"
echo "file3"
echo "file4"
echo "file5"
} > "$T_YADM_ENCRYPT"
EXPECT_INCLUDE=("file1" "file3" "file5")
run_parse
[ "$status" == 0 ]
[ "$output" == "" ]
[ "${#ENCRYPT_INCLUDE_FILES[@]}" -eq "${#EXPECT_INCLUDE[@]}" ]
[ "${ENCRYPT_INCLUDE_FILES[*]}" == "${EXPECT_INCLUDE[*]}" ]
}
@test "parse_encrypt (files and dirs)" {
echo "
.yadm/encrypt is references present and missing files
.yadm/encrypt is references present and missing dirs
Array should be as expected
"
mkdir -p "$T_DIR_WORK/dir1"
mkdir -p "$T_DIR_WORK/dir2"
echo "file1" > "$T_DIR_WORK/file1"
echo "file2" > "$T_DIR_WORK/file2"
echo "a" > "$T_DIR_WORK/dir1/a"
echo "b" > "$T_DIR_WORK/dir1/b"
{ echo "file1"
echo "file2"
echo "file3"
echo "dir1"
echo "dir2"
echo "dir3"
} > "$T_YADM_ENCRYPT"
EXPECT_INCLUDE=("file1" "file2" "dir1" "dir2")
run_parse
[ "$status" == 0 ]
[ "$output" == "" ]
[ "${#ENCRYPT_INCLUDE_FILES[@]}" -eq "${#EXPECT_INCLUDE[@]}" ]
[ "${ENCRYPT_INCLUDE_FILES[*]}" == "${EXPECT_INCLUDE[*]}" ]
}
@test "parse_encrypt (comments/empty lines)" {
echo "
.yadm/encrypt is references present and missing files
.yadm/encrypt is references present and missing dirs
.yadm/encrypt contains comments / blank lines
Array should be as expected
"
mkdir -p "$T_DIR_WORK/dir1"
mkdir -p "$T_DIR_WORK/dir2"
echo "file1" > "$T_DIR_WORK/file1"
echo "file2" > "$T_DIR_WORK/file2"
echo "file3" > "$T_DIR_WORK/file3"
echo "a" > "$T_DIR_WORK/dir1/a"
echo "b" > "$T_DIR_WORK/dir1/b"
{ echo "file1"
echo "file2"
echo "#file3"
echo " #file3"
echo ""
echo "dir1"
echo "dir2"
echo "dir3"
} > "$T_YADM_ENCRYPT"
EXPECT_INCLUDE=("file1" "file2" "dir1" "dir2")
run_parse
[ "$status" == 0 ]
[ "$output" == "" ]
[ "${#ENCRYPT_INCLUDE_FILES[@]}" -eq "${#EXPECT_INCLUDE[@]}" ]
[ "${ENCRYPT_INCLUDE_FILES[*]}" == "${EXPECT_INCLUDE[*]}" ]
}
@test "parse_encrypt (w/spaces)" {
echo "
.yadm/encrypt is references present and missing files
.yadm/encrypt is references present and missing dirs
.yadm/encrypt references contain spaces
Array should be as expected
"
mkdir -p "$T_DIR_WORK/di r1"
mkdir -p "$T_DIR_WORK/dir2"
echo "file1" > "$T_DIR_WORK/file1"
echo "fi le2" > "$T_DIR_WORK/fi le2"
echo "file3" > "$T_DIR_WORK/file3"
echo "a" > "$T_DIR_WORK/di r1/a"
echo "b" > "$T_DIR_WORK/di r1/b"
{ echo "file1"
echo "fi le2"
echo "#file3"
echo " #file3"
echo ""
echo "di r1"
echo "dir2"
echo "dir3"
} > "$T_YADM_ENCRYPT"
EXPECT_INCLUDE=("file1" "fi le2" "di r1" "dir2")
run_parse
[ "$status" == 0 ]
[ "$output" == "" ]
[ "${#ENCRYPT_INCLUDE_FILES[@]}" -eq "${#EXPECT_INCLUDE[@]}" ]
[ "${ENCRYPT_INCLUDE_FILES[*]}" == "${EXPECT_INCLUDE[*]}" ]
}
@test "parse_encrypt (wildcards)" {
echo "
.yadm/encrypt contains wildcards
Array should be as expected
"
mkdir -p "$T_DIR_WORK/di r1"
mkdir -p "$T_DIR_WORK/dir2"
echo "file1" > "$T_DIR_WORK/file1"
echo "fi le2" > "$T_DIR_WORK/fi le2"
echo "file2" > "$T_DIR_WORK/file2"
echo "file3" > "$T_DIR_WORK/file3"
echo "a" > "$T_DIR_WORK/di r1/a"
echo "b" > "$T_DIR_WORK/di r1/b"
{ echo "fi*"
echo "#file3"
echo " #file3"
echo ""
echo "#dir2"
echo "di r1"
echo "dir2"
echo "dir3"
} > "$T_YADM_ENCRYPT"
EXPECT_INCLUDE=("fi le2" "file1" "file2" "file3" "di r1" "dir2")
run_parse
[ "$status" == 0 ]
[ "$output" == "" ]
[ "${#ENCRYPT_INCLUDE_FILES[@]}" -eq "${#EXPECT_INCLUDE[@]}" ]
[ "${ENCRYPT_INCLUDE_FILES[*]}" == "${EXPECT_INCLUDE[*]}" ]
}
@test "parse_encrypt (excludes)" {
echo "
.yadm/encrypt contains exclusions
Array should be as expected
"
mkdir -p "$T_DIR_WORK/di r1"
mkdir -p "$T_DIR_WORK/dir2"
mkdir -p "$T_DIR_WORK/dir3"
echo "file1" > "$T_DIR_WORK/file1"
echo "file1.ex" > "$T_DIR_WORK/file1.ex"
echo "fi le2" > "$T_DIR_WORK/fi le2"
echo "file3" > "$T_DIR_WORK/file3"
echo "test" > "$T_DIR_WORK/test"
echo "a.txt" > "$T_DIR_WORK/di r1/a.txt"
echo "b.txt" > "$T_DIR_WORK/di r1/b.txt"
echo "c.inc" > "$T_DIR_WORK/di r1/c.inc"
{ echo "fi*"
echo "#file3"
echo " #file3"
echo ""
echo " #test"
echo "#dir2"
echo "di r1/*"
echo "dir2"
echo "dir3"
echo "dir4"
echo "!*.ex"
echo "!di r1/*.txt"
} > "$T_YADM_ENCRYPT"
EXPECT_INCLUDE=("fi le2" "file1" "file3" "di r1/c.inc" "dir2" "dir3")
run_parse
[ "$status" == 0 ]
[ "$output" == "" ]
[ "${#ENCRYPT_INCLUDE_FILES[@]}" -eq "${#EXPECT_INCLUDE[@]}" ]
[ "${ENCRYPT_INCLUDE_FILES[*]}" == "${EXPECT_INCLUDE[*]}" ]
}

View File

@ -440,3 +440,140 @@ EOF
remote_output=$(GIT_DIR="$T_DIR_REPO" git remote show)
[ "$remote_output" = "origin" ]
}
@test "Command 'clone' (local insecure .ssh and .gnupg data, no related data in repo)" {
echo "
Local .ssh/.gnupg data exists and is insecure
but yadm repo contains no .ssh/.gnupg data
local insecure data should remain accessible
(yadm is hands-off)
"
#; setup scenario
rm -rf "$T_DIR_WORK" "$T_DIR_REPO"
mkdir -p "$T_DIR_WORK/.ssh"
mkdir -p "$T_DIR_WORK/.gnupg"
touch "$T_DIR_WORK/.ssh/testfile"
touch "$T_DIR_WORK/.gnupg/testfile"
find "$T_DIR_WORK" -exec chmod a+rw '{}' ';'
#; run clone (with debug on)
run "${T_YADM_Y[@]}" clone -d -w "$T_DIR_WORK" "$REMOTE_URL"
#; validate status and output
[ "$status" -eq 0 ]
[[ "$output" =~ Initialized ]]
[[ "$output" =~ initial\ private\ dir\ perms\ drwxrwxrwx.+\.ssh ]]
[[ "$output" =~ initial\ private\ dir\ perms\ drwxrwxrwx.+\.gnupg ]]
[[ "$output" =~ pre-merge\ private\ dir\ perms\ drwxrwxrwx.+\.ssh ]]
[[ "$output" =~ pre-merge\ private\ dir\ perms\ drwxrwxrwx.+\.gnupg ]]
[[ "$output" =~ post-merge\ private\ dir\ perms\ drwxrwxrwx.+\.ssh ]]
[[ "$output" =~ post-merge\ private\ dir\ perms\ drwxrwxrwx.+\.gnupg ]]
# standard perms still apply afterwards unless disabled with auto.perms
test_perms "$T_DIR_WORK/.gnupg" "drwx------"
test_perms "$T_DIR_WORK/.ssh" "drwx------"
}
@test "Command 'clone' (local insecure .gnupg data, related data in repo)" {
echo "
Local .gnupg data exists and is insecure
and yadm repo contains .gnupg data
.gnupg dir should be secured post merge
"
#; setup scenario
IN_REPO=(.bash_profile .vimrc .gnupg/gpg.conf)
setup
rm -rf "$T_DIR_WORK" "$T_DIR_REPO"
mkdir -p "$T_DIR_WORK/.gnupg"
touch "$T_DIR_WORK/.gnupg/testfile"
find "$T_DIR_WORK" -exec chmod a+rw '{}' ';'
#; run clone (with debug on)
run "${T_YADM_Y[@]}" clone -d -w "$T_DIR_WORK" "$REMOTE_URL"
#; validate status and output
[ "$status" -eq 0 ]
[[ "$output" =~ Initialized ]]
[[ "$output" =~ initial\ private\ dir\ perms\ drwxrwxrwx.+\.gnupg ]]
[[ "$output" =~ pre-merge\ private\ dir\ perms\ drwxrwxrwx.+\.gnupg ]]
[[ "$output" =~ post-merge\ private\ dir\ perms\ drwxrwxrwx.+\.gnupg ]]
test_perms "$T_DIR_WORK/.gnupg" "drwx------"
}
@test "Command 'clone' (local insecure .ssh data, related data in repo)" {
echo "
Local .ssh data exists and is insecure
and yadm repo contains .ssh data
.ssh dir should be secured post merge
"
#; setup scenario
IN_REPO=(.bash_profile .vimrc .ssh/config)
setup
rm -rf "$T_DIR_WORK" "$T_DIR_REPO"
mkdir -p "$T_DIR_WORK/.ssh"
touch "$T_DIR_WORK/.ssh/testfile"
find "$T_DIR_WORK" -exec chmod a+rw '{}' ';'
#; run clone (with debug on)
run "${T_YADM_Y[@]}" clone -d -w "$T_DIR_WORK" "$REMOTE_URL"
#; validate status and output
[ "$status" -eq 0 ]
[[ "$output" =~ Initialized ]]
[[ "$output" =~ initial\ private\ dir\ perms\ drwxrwxrwx.+\.ssh ]]
[[ "$output" =~ pre-merge\ private\ dir\ perms\ drwxrwxrwx.+\.ssh ]]
[[ "$output" =~ post-merge\ private\ dir\ perms\ drwxrwxrwx.+\.ssh ]]
test_perms "$T_DIR_WORK/.ssh" "drwx------"
}
@test "Command 'clone' (no existing .gnupg, .gnupg data tracked in repo)" {
echo "
Local .gnupg does not exist
and yadm repo contains .gnupg data
.gnupg dir should be created and secured prior to merge
tracked .gnupg data should be user accessible only
"
#; setup scenario
IN_REPO=(.bash_profile .vimrc .gnupg/gpg.conf)
setup
rm -rf "$T_DIR_WORK"
mkdir -p "$T_DIR_WORK"
rm -rf "$T_DIR_REPO"
#; run clone (with debug on)
run "${T_YADM_Y[@]}" clone -d -w "$T_DIR_WORK" "$REMOTE_URL"
#; validate status and output
[ "$status" -eq 0 ]
[[ "$output" =~ Initialized ]]
[[ ! "$output" =~ initial\ private\ dir\ perms ]]
[[ "$output" =~ pre-merge\ private\ dir\ perms\ drwx------.+\.gnupg ]]
[[ "$output" =~ post-merge\ private\ dir\ perms\ drwx------.+\.gnupg ]]
test_perms "$T_DIR_WORK/.gnupg" "drwx------"
}
@test "Command 'clone' (no existing .ssh, .ssh data tracked in repo)" {
echo "
Local .ssh does not exist
and yadm repo contains .ssh data
.ssh dir should be created and secured prior to merge
tracked .ssh data should be user accessible only
"
#; setup scenario
IN_REPO=(.bash_profile .vimrc .ssh/config)
setup
rm -rf "$T_DIR_WORK"
mkdir -p "$T_DIR_WORK"
rm -rf "$T_DIR_REPO"
#; run clone (with debug on)
run "${T_YADM_Y[@]}" clone -d -w "$T_DIR_WORK" "$REMOTE_URL"
#; validate status and output
[ "$status" -eq 0 ]
[[ "$output" =~ Initialized ]]
[[ ! "$output" =~ initial\ private\ dir\ perms ]]
[[ "$output" =~ pre-merge\ private\ dir\ perms\ drwx------.+\.ssh ]]
[[ "$output" =~ post-merge\ private\ dir\ perms\ drwx------.+\.ssh ]]
test_perms "$T_DIR_WORK/.ssh" "drwx------"
}

View File

@ -4,15 +4,20 @@ status=;output=; #; populated by bats run()
IN_REPO=(alt* "dir one")
export TEST_TREE_WITH_ALT=1
EXCLUDED_NAME="excluded-base"
function create_encrypt() {
for efile in "encrypted-base##" "encrypted-system##$T_SYS" "encrypted-host##$T_SYS.$T_HOST" "encrypted-user##$T_SYS.$T_HOST.$T_USER"; do
echo "$efile" >> "$T_YADM_ENCRYPT"
echo "$efile" >> "$T_DIR_WORK/$efile"
mkdir -p "$T_DIR_WORK/dir one/$efile"
echo "'dir one'/$efile/file1" >> "$T_YADM_ENCRYPT"
echo "dir one/$efile/file1" >> "$T_YADM_ENCRYPT"
echo "dir one/$efile/file1" >> "$T_DIR_WORK/dir one/$efile/file1"
done
echo "$EXCLUDED_NAME##" >> "$T_YADM_ENCRYPT"
echo "!$EXCLUDED_NAME##" >> "$T_YADM_ENCRYPT"
echo "$EXCLUDED_NAME##" >> "$T_DIR_WORK/$EXCLUDED_NAME##"
}
setup() {
@ -130,6 +135,12 @@ function test_alt() {
fi
fi
if [ -L "$T_DIR_WORK/$EXCLUDED_NAME" ] ; then
echo "ERROR: Found link: $T_DIR_WORK/$EXCLUDED_NAME"
echo "ERROR: Excluded files should not be linked"
return 1
fi
#; validate link content
if [[ "$alt_type" =~ none ]] || [ "$auto_alt" = "false" ]; then
#; no link should be present

View File

@ -88,6 +88,8 @@ EOF
"$T_GPG_PROGRAM" -q -d "$T_YADM_ARCHIVE" | tar t | sort > "$T_TMP/archive_list"
fi
excluded="$2"
#; inventory what is expected in the archive
(
if cd "$T_DIR_WORK"; then
@ -95,10 +97,23 @@ EOF
# (globbing is desired)
while IFS='' read -r glob || [ -n "$glob" ]; do
if [[ ! $glob =~ ^# && ! $glob =~ ^[[:space:]]*$ ]] ; then
if [[ ! $glob =~ ^!(.+) ]] ; then
local IFS=$'\n'
for matching_file in $(eval ls "$glob" 2>/dev/null); do
echo "$matching_file"
for matching_file in $glob; do
if [ -e "$matching_file" ]; then
if [ "$matching_file" != "$excluded" ]; then
if [ -d "$matching_file" ]; then
echo "$matching_file/"
for subfile in "$matching_file"/*; do
echo "$subfile"
done
else
echo "$matching_file"
fi
fi
fi
done
fi
fi
done < "$T_YADM_ENCRYPT" | sort > "$T_TMP/expected_list"
fi
@ -290,7 +305,77 @@ EOF
#; add paths with spaces to YADM_ARCHIVE
local original_encrypt
original_encrypt=$(cat "$T_YADM_ENCRYPT")
echo -e "'space test'/file*" >> "$T_YADM_ENCRYPT"
echo -e "space test/file*" >> "$T_YADM_ENCRYPT"
#; run encrypt
run expect <<EOF
set timeout 2;
spawn ${T_YADM_Y[*]} encrypt;
expect "passphrase:" {send "$T_PASSWD\n"}
expect "passphrase:" {send "$T_PASSWD\n"}
expect "$"
foreach {pid spawnid os_error_flag value} [wait] break
exit \$value
EOF
#; validate status and output
[ "$status" -eq 0 ]
[[ "$output" =~ Wrote\ new\ file:.+$T_YADM_ARCHIVE ]]
#; validate the archive
validate_archive symmetric
}
@test "Command 'encrypt' (exclusions in YADM_ENCRYPT)" {
echo "
When 'encrypt' command is provided,
and YADM_ENCRYPT is present
Create YADM_ARCHIVE
Report the archive created
Archive should be valid
Exit with 0
"
#; add paths with spaces to YADM_ARCHIVE
local original_encrypt
original_encrypt=$(cat "$T_YADM_ENCRYPT")
echo -e ".ssh/*" >> "$T_YADM_ENCRYPT"
echo -e "!.ssh/sec*.pub" >> "$T_YADM_ENCRYPT"
#; run encrypt
run expect <<EOF
set timeout 2;
spawn ${T_YADM_Y[*]} encrypt;
expect "passphrase:" {send "$T_PASSWD\n"}
expect "passphrase:" {send "$T_PASSWD\n"}
expect "$"
foreach {pid spawnid os_error_flag value} [wait] break
exit \$value
EOF
#; validate status and output
[ "$status" -eq 0 ]
[[ "$output" =~ Wrote\ new\ file:.+$T_YADM_ARCHIVE ]]
[[ ! "$output" =~ \.ssh/secret.pub ]]
#; validate the archive
validate_archive symmetric ".ssh/secret.pub"
}
@test "Command 'encrypt' (directories in YADM_ENCRYPT)" {
echo "
When 'encrypt' command is provided,
and YADM_ENCRYPT is present
Create YADM_ARCHIVE
Report the archive created
Archive should be valid
Exit with 0
"
#; add directory paths to YADM_ARCHIVE
local original_encrypt
original_encrypt=$(cat "$T_YADM_ENCRYPT")
echo -e "space test" >> "$T_YADM_ENCRYPT"
#; run encrypt
run expect <<EOF

View File

@ -27,13 +27,8 @@ function validate_perms() {
gpg)
restricted=("${restricted[@]}" $T_DIR_WORK/.gnupg $T_DIR_WORK/.gnupg/*)
;;
encrypt)
local glob
while IFS='' read -r glob || [ -n "$glob" ]; do
if [[ ! $glob =~ ^# ]] ; then
restricted=("${restricted[@]}" $T_DIR_WORK/$glob)
fi
done < "$T_YADM_ENCRYPT"
*)
restricted=("${restricted[@]}" $T_DIR_WORK/$p)
;;
esac
done
@ -80,7 +75,7 @@ function validate_perms() {
"
#; this version has a comment in it
echo -e "#.vimrc\n.hammerspoon/*" > "$T_YADM_ENCRYPT"
echo -e "#.vimrc\n.tmux.conf\n.hammerspoon/*\n!.tmux.conf" > "$T_YADM_ENCRYPT"
#; run perms
run "${T_YADM_Y[@]}" perms
@ -89,11 +84,8 @@ function validate_perms() {
[ "$status" -eq 0 ]
[ "$output" = "" ]
#; this version has no comments in it
echo -e ".hammerspoon/*" > "$T_YADM_ENCRYPT"
#; validate permissions
validate_perms ssh gpg encrypt
validate_perms ssh gpg ".hammerspoon/*"
}
@test "Command 'perms' (ssh-perms=false)" {

View File

@ -9,6 +9,11 @@ export TEST_TREE_WITH_ALT=1
setup() {
destroy_tmp
build_repo "${IN_REPO[@]}"
echo "excluded-encrypt##yadm.j2" > "$T_YADM_ENCRYPT"
echo "included-encrypt##yadm.j2" >> "$T_YADM_ENCRYPT"
echo "!excluded-encrypt*" >> "$T_YADM_ENCRYPT"
echo "included-encrypt" > "$T_DIR_WORK/included-encrypt##yadm.j2"
echo "excluded-encrypt" > "$T_DIR_WORK/excluded-encrypt##yadm.j2"
}
@ -27,6 +32,11 @@ function test_alt() {
real_name="alt-jinja"
file_content_match="custom_class-custom_system-custom_host-custom_user-${T_DISTRO}"
;;
encrypt)
real_name="included-encrypt"
file_content_match="included-encrypt"
missing_name="excluded-encrypt"
;;
esac
if [ "$test_overwrite" = "true" ] ; then
@ -63,6 +73,11 @@ function test_alt() {
fi
fi
if [ -n "$missing_name" ] && [ -f "$T_DIR_WORK/$missing_name" ]; then
echo "ERROR: File should not have been created '$missing_name'"
return 1
fi
#; validate link content
if [[ "$alt_type" =~ none ]] || [ "$auto_alt" = "false" ]; then
#; no real file should be present
@ -173,3 +188,16 @@ function test_alt() {
GIT_DIR="$T_DIR_REPO" git config local.class custom_class
test_alt 'override_all' 'false' ''
}
@test "Command 'alt' (select jinja within .yadm/encrypt)" {
echo "
When the command 'alt' is provided
and file matches ##yadm.j2 within .yadm/encrypt
and file excluded within .yadm/encrypt
Report jinja template processing
Verify that the correct content is written
Exit with 0
"
test_alt 'encrypt' 'false' ''
}

View File

@ -73,7 +73,7 @@ function count_introspect() {
Exit with 0
"
count_introspect "configs" 0 12 'yadm\.auto-alt'
count_introspect "configs" 0 13 'yadm\.auto-alt'
}
@test "Command 'introspect' (repo)" {

View File

@ -0,0 +1,102 @@
load common
load_fixtures
status=;output=; #; populated by bats run()
IN_REPO=(.bash_profile .vimrc)
setup() {
destroy_tmp
build_repo "${IN_REPO[@]}"
rm -rf "$T_DIR_WORK"
mkdir -p "$T_DIR_WORK"
}
@test "Private dirs (private dirs missing)" {
echo "
When a git command is run
And private directories are missing
Create private directories prior to command
"
#; confirm directories are missing at start
[ ! -e "$T_DIR_WORK/.gnupg" ]
[ ! -e "$T_DIR_WORK/.ssh" ]
#; run status
export DEBUG=yes
run "${T_YADM_Y[@]}" status
#; validate status and output
[ "$status" -eq 0 ]
[[ "$output" =~ On\ branch\ master ]]
#; confirm private directories are created
[ -d "$T_DIR_WORK/.gnupg" ]
test_perms "$T_DIR_WORK/.gnupg" "drwx------"
[ -d "$T_DIR_WORK/.ssh" ]
test_perms "$T_DIR_WORK/.ssh" "drwx------"
#; confirm directories are created before command is run
[[ "$output" =~ Creating.+/.gnupg/.+Creating.+/.ssh/.+Running\ git\ command\ git\ status ]]
}
@test "Private dirs (private dirs missing / yadm.auto-private-dirs=false)" {
echo "
When a git command is run
And private directories are missing
But auto-private-dirs is false
Do not create private dirs
"
#; confirm directories are missing at start
[ ! -e "$T_DIR_WORK/.gnupg" ]
[ ! -e "$T_DIR_WORK/.ssh" ]
#; set configuration
run "${T_YADM_Y[@]}" config --bool "yadm.auto-private-dirs" "false"
#; run status
run "${T_YADM_Y[@]}" status
#; validate status and output
[ "$status" -eq 0 ]
[[ "$output" =~ On\ branch\ master ]]
#; confirm private directories are not created
[ ! -e "$T_DIR_WORK/.gnupg" ]
[ ! -e "$T_DIR_WORK/.ssh" ]
}
@test "Private dirs (private dirs exist / yadm.auto-perms=false)" {
echo "
When a git command is run
And private directories exist
And yadm is configured not to auto update perms
Do not alter directories
"
#shellcheck disable=SC2174
mkdir -m 0777 -p "$T_DIR_WORK/.gnupg" "$T_DIR_WORK/.ssh"
#; confirm directories are preset and open
[ -d "$T_DIR_WORK/.gnupg" ]
test_perms "$T_DIR_WORK/.gnupg" "drwxrwxrwx"
[ -d "$T_DIR_WORK/.ssh" ]
test_perms "$T_DIR_WORK/.ssh" "drwxrwxrwx"
#; set configuration
run "${T_YADM_Y[@]}" config --bool "yadm.auto-perms" "false"
#; run status
run "${T_YADM_Y[@]}" status
#; validate status and output
[ "$status" -eq 0 ]
[[ "$output" =~ On\ branch\ master ]]
#; confirm directories are still preset and open
[ -d "$T_DIR_WORK/.gnupg" ]
test_perms "$T_DIR_WORK/.gnupg" "drwxrwxrwx"
[ -d "$T_DIR_WORK/.ssh" ]
test_perms "$T_DIR_WORK/.ssh" "drwxrwxrwx"
}

221
yadm
View File

@ -19,7 +19,7 @@ if [ -z "$BASH_VERSION" ]; then
[ "$YADM_TEST" != 1 ] && exec bash "$0" "$@"
fi
VERSION=1.11.0
VERSION=1.12.0
YADM_WORK="$HOME"
YADM_DIR="$HOME/.yadm"
@ -35,13 +35,14 @@ FULL_COMMAND=""
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"
ENCRYPT_INCLUDE_FILES="unparsed"
#; flag causing path translations with cygpath
USE_CYGPATH=0
@ -128,6 +129,7 @@ function main() {
function alt() {
require_repo
parse_encrypt
local_class="$(config local.class)"
if [ -z "$local_class" ] ; then
@ -160,32 +162,11 @@ function alt() {
match1="^(.+)##(()|$match_system|$match_system\.$match_host|$match_system\.$match_host\.$match_user)$"
match2="^(.+)##($match_class|$match_class\.$match_system|$match_class\.$match_system\.$match_host|$match_class\.$match_system\.$match_host\.$match_user)$"
#; process relative to YADM_WORK
YADM_WORK=$(unix_path "$("$GIT_PROGRAM" config core.worktree)")
cd "$YADM_WORK" || {
debug "Alternates not processed, unable to cd to $YADM_WORK"
return
}
cd_work "Alternates" || return
#; only be noisy if the "alt" command was run directly
[ "$YADM_COMMAND" = "alt" ] && loud="YES"
#; build a list of files from YADM_ENCRYPT
ENC_FILES=()
index=0
if [ -f "$YADM_ENCRYPT" ] ; then
while IFS='' read -r glob || [ -n "$glob" ]; do
if [[ ! $glob =~ ^# && ! $glob =~ ^[[:space:]]*$ ]] ; then
# echo "working on ->$glob<-"
local IFS=$'\n'
for matching_file in $(eval "$LS_PROGRAM" "$glob" 2>/dev/null); do
ENC_FILES[$index]="$matching_file"
((index++))
done
fi
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
@ -199,7 +180,7 @@ function alt() {
for match in $match1 $match2; do
last_linked=''
local IFS=$'\n'
for tracked_file in $("$GIT_PROGRAM" ls-files | sort) "${ENC_FILES[@]}"; do
for tracked_file in $("$GIT_PROGRAM" ls-files | sort) "${ENCRYPT_INCLUDE_FILES[@]}"; do
tracked_file="$YADM_WORK/$tracked_file"
#; process both the path, and it's parent directory
for alt_path in "$tracked_file" "${tracked_file%/*}"; do
@ -229,7 +210,7 @@ function alt() {
#; for every file which is a *##yadm.j2 create a real file
local IFS=$'\n'
local match="^(.+)##yadm\\.j2$"
for tracked_file in $("$GIT_PROGRAM" ls-files | sort) $(cat "$YADM_ENCRYPT" 2>/dev/null); do
for tracked_file in $("$GIT_PROGRAM" ls-files | sort) "${ENCRYPT_INCLUDE_FILES[@]}"; do
tracked_file="$YADM_WORK/$tracked_file"
if [ -e "$tracked_file" ] ; then
if [[ $tracked_file =~ $match ]] ; then
@ -292,6 +273,8 @@ function clone() {
shift
done
[ -n "$DEBUG" ] && display_private_perms "initial"
#; clone will begin with a bare repo
local empty=
init $empty
@ -310,6 +293,15 @@ function clone() {
rm -rf "$YADM_REPO"
error_out "Unable to fetch origin ${clone_args[0]}"
}
debug "Determining if repo tracks private directories"
for private_dir in .ssh/ .gnupg/; do
found_log=$("$GIT_PROGRAM" log -n 1 origin/master -- "$private_dir" 2>/dev/null)
if [ -n "$found_log" ]; then
debug "Private directory $private_dir is tracked by repo"
assert_private_dirs "$private_dir"
fi
done
[ -n "$DEBUG" ] && display_private_perms "pre-merge"
debug "Doing an initial merge of origin/master"
"$GIT_PROGRAM" merge origin/master || {
debug "Merge failed, doing a reset and stashing conflicts."
@ -351,6 +343,8 @@ EOF
fi
}
[ -n "$DEBUG" ] && display_private_perms "post-merge"
CHANGES_POSSIBLE=1
}
@ -422,14 +416,9 @@ function encrypt() {
require_gpg
require_encrypt
require_ls
parse_encrypt
#; process relative to YADM_WORK
YADM_WORK=$(unix_path "$("$GIT_PROGRAM" config core.worktree)")
cd "$YADM_WORK" || {
debug "Encryption not processed, unable to cd to $YADM_WORK"
return
}
cd_work "Encryption" || return
#; Build gpg options for gpg
GPG_KEY="$(config yadm.gpg-recipient)"
@ -441,26 +430,13 @@ function encrypt() {
GPG_OPTS=("-c")
fi
#; build a list of files from YADM_ENCRYPT
ENC_FILES=()
index=0
while IFS='' read -r glob || [ -n "$glob" ]; do
if [[ ! $glob =~ ^# && ! $glob =~ ^[[:space:]]*$ ]] ; then
local IFS=$'\n'
for matching_file in $(eval "$LS_PROGRAM" "$glob" 2>/dev/null); do
ENC_FILES[$index]="$matching_file"
((index++))
done
fi
done < "$YADM_ENCRYPT"
#; report which files will be encrypted
echo "Encrypting the following files:"
"$LS_PROGRAM" -1 "${ENC_FILES[@]}"
printf '%s\n' "${ENCRYPT_INCLUDE_FILES[@]}"
echo
#; encrypt all files which match the globs
if tar -f - -c "${ENC_FILES[@]}" | $GPG_PROGRAM --yes "${GPG_OPTS[@]}" --output "$YADM_ARCHIVE"; then
if tar -f - -c "${ENCRYPT_INCLUDE_FILES[@]}" | $GPG_PROGRAM --yes "${GPG_OPTS[@]}" --output "$YADM_ARCHIVE"; then
echo "Wrote new file: $YADM_ARCHIVE"
else
error_out "Unable to write $YADM_ARCHIVE"
@ -513,9 +489,18 @@ function git_command() {
set -- "config" "${@:2}"
fi
#; ensure private .ssh and .gnupg directories exist first
#; TODO: consider restricting this to only commands which modify the work-tree
auto_private_dirs=$(config --bool yadm.auto-private-dirs)
if [ "$auto_private_dirs" != "false" ] ; then
assert_private_dirs .gnupg/ .ssh/
fi
CHANGES_POSSIBLE=1
#; pass commands through to git
debug "Running git command $GIT_PROGRAM $*"
"$GIT_PROGRAM" "$@"
return "$?"
}
@ -613,6 +598,7 @@ local.os
local.user
yadm.auto-alt
yadm.auto-perms
yadm.auto-private-dirs
yadm.cygwin-copy
yadm.git-program
yadm.gpg-perms
@ -644,11 +630,7 @@ function list() {
#; process relative to YADM_WORK when --all is specified
if [ -n "$LIST_ALL" ] ; then
YADM_WORK=$(unix_path "$("$GIT_PROGRAM" config core.worktree)")
cd "$YADM_WORK" || {
debug "List not processed, unable to cd to $YADM_WORK"
return
}
cd_work "List" || return
fi
#; list tracked files
@ -658,40 +640,29 @@ function list() {
function perms() {
require_ls
parse_encrypt
#; TODO: prevent repeats in the files changed
#; process relative to YADM_WORK
YADM_WORK=$(unix_path "$("$GIT_PROGRAM" config core.worktree)")
cd "$YADM_WORK" || {
debug "Perms not processed, unable to cd to $YADM_WORK"
return
}
cd_work "Perms" || return
GLOBS=()
#; include the archive created by "encrypt"
[ -f "$YADM_ARCHIVE" ] && GLOBS=("${GLOBS[@]}" "$YADM_ARCHIVE")
[ -f "$YADM_ARCHIVE" ] && GLOBS+=("$YADM_ARCHIVE")
#; include all .ssh files (unless disabled)
if [[ $(config --bool yadm.ssh-perms) != "false" ]] ; then
GLOBS=("${GLOBS[@]}" ".ssh" ".ssh/*")
GLOBS+=(".ssh" ".ssh/*")
fi
#; include all gpg files (unless disabled)
if [[ $(config --bool yadm.gpg-perms) != "false" ]] ; then
GLOBS=("${GLOBS[@]}" ".gnupg" ".gnupg/*")
GLOBS+=(".gnupg" ".gnupg/*")
fi
#; include globs found in YADM_ENCRYPT (if present)
if [ -f "$YADM_ENCRYPT" ] ; then
while IFS='' read -r glob || [ -n "$glob" ]; do
if [[ ! $glob =~ ^# ]] ; then
GLOBS=("${GLOBS[@]}" $(eval "$LS_PROGRAM" "$glob" 2>/dev/null))
fi
done < "$YADM_ENCRYPT"
fi
#; include any files we encrypt
GLOBS+=("${ENCRYPT_INCLUDE_FILES[@]}")
#; remove group/other permissions from collected globs
#shellcheck disable=SC2068
@ -852,13 +823,13 @@ function set_operating_system() {
function debug() {
[ -n "$DEBUG" ] && echo -e "DEBUG: $*"
[ -n "$DEBUG" ] && echo_e "DEBUG: $*"
}
function error_out() {
echo -e "ERROR: $*"
echo_e "ERROR: $*"
exit_with_hook 1
}
@ -906,6 +877,89 @@ function invoke_hook() {
}
function assert_private_dirs() {
work=$(unix_path "$("$GIT_PROGRAM" config core.worktree)")
for private_dir in "$@"; do
if [ ! -d "$work/$private_dir" ]; then
debug "Creating $work/$private_dir"
#shellcheck disable=SC2174
mkdir -m 0700 -p "$work/$private_dir" >/dev/null 2>&1
fi
done
}
function display_private_perms() {
when="$1"
for private_dir in .ssh .gnupg; do
if [ -d "$YADM_WORK/$private_dir" ]; then
private_perms=$(ls -ld "$YADM_WORK/$private_dir")
debug "$when" private dir perms "$private_perms"
fi
done
}
function cd_work() {
YADM_WORK=$(unix_path "$("$GIT_PROGRAM" config core.worktree)")
cd "$YADM_WORK" || {
debug "$1 not processed, unable to cd to $YADM_WORK"
return 1
}
return 0
}
function parse_encrypt() {
if [ "$ENCRYPT_INCLUDE_FILES" != "unparsed" ]; then
#shellcheck disable=SC2034
PARSE_ENCRYPT_SHORT="parse_encrypt() not reprocessed"
return
fi
ENCRYPT_INCLUDE_FILES=()
ENCRYPT_EXCLUDE_FILES=()
cd_work "Parsing encrypt" || return
exclude_pattern="^!(.+)"
if [ -f "$YADM_ENCRYPT" ] ; then
#; parse both included/excluded
while IFS='' read -r line || [ -n "$line" ]; do
if [[ ! $line =~ ^# && ! $line =~ ^[[:space:]]*$ ]] ; then
local IFS=$'\n'
for pattern in $line; do
if [[ "$pattern" =~ $exclude_pattern ]]; then
for ex_file in ${BASH_REMATCH[1]}; do
if [ -e "$ex_file" ]; then
ENCRYPT_EXCLUDE_FILES+=("$ex_file")
fi
done
else
for in_file in $pattern; do
if [ -e "$in_file" ]; then
ENCRYPT_INCLUDE_FILES+=("$in_file")
fi
done
fi
done
fi
done < "$YADM_ENCRYPT"
#; remove excludes from the includes
#(SC2068 is disabled because in this case, we desire globbing)
FINAL_INCLUDE=()
#shellcheck disable=SC2068
for included in "${ENCRYPT_INCLUDE_FILES[@]}"; do
skip=
#shellcheck disable=SC2068
for ex_file in ${ENCRYPT_EXCLUDE_FILES[@]}; do
[ "$included" == "$ex_file" ] && { skip=1; break; }
done
[ -n "$skip" ] || FINAL_INCLUDE+=("$included")
done
ENCRYPT_INCLUDE_FILES=("${FINAL_INCLUDE[@]}")
fi
}
#; ****** Auto Functions ******
function auto_alt() {
@ -990,13 +1044,6 @@ function require_gpg() {
function require_repo() {
[ -d "$YADM_REPO" ] || error_out "Git repo does not exist. did you forget to run 'init' or 'clone'?"
}
function require_ls() {
if [ ! -f "$LS_PROGRAM" ] ; then
command -v ls >/dev/null 2>&1 || \
error_out "This functionality requires 'ls' to be installed at '$LS_PROGRAM' or listed in your \$PATH"
LS_PROGRAM=ls
fi
}
function require_shell() {
[ -x "$SHELL" ] || error_out "\$SHELL does not refer to an executable."
}
@ -1028,6 +1075,20 @@ function mixed_path() {
fi
}
#; ****** echo replacements ******
function echo() {
IFS=' '
printf '%s\n' "$*"
}
function echo_n() {
IFS=' '
printf '%s' "$*"
}
function echo_e() {
IFS=' '
printf '%b\n' "$*"
}
#; ****** Main processing (when not unit testing) ******
if [ "$YADM_TEST" != 1 ] ; then

45
yadm.1
View File

@ -1,5 +1,5 @@
." vim: set spell so=8:
.TH yadm 1 "10 July 2017" "1.11.0"
.TH yadm 1 "25 October 2017" "1.12.0"
.SH NAME
yadm \- Yet Another Dotfiles Manager
.SH SYNOPSIS
@ -350,6 +350,9 @@ If disabled, you may still run
manually to update permissions.
This feature is enabled by default.
.TP
.B yadm.auto-private-dirs
Disable the automatic creating of private directories described in the section PERMISSIONS.
.TP
.B yadm.ssh-perms
Disable the permission changes to
.IR $HOME/.ssh/* .
@ -583,6 +586,11 @@ For example:
.gnupg/*.gpg
.RE
Standard filename expansions (*, ?, [) are supported. Other shell expansions
like brace and tilde are not supported. Spaces in paths are supported, and
should not be quoted. If a directory is specified, its contents will be
included, but not recursively. Paths beginning with a "!" will be excluded.
The
.B yadm encrypt
command will find all files matching the patterns, and prompt for a password. Once a
@ -608,12 +616,10 @@ It is recommended that you use a private repository when keeping confidential
files, even though they are encrypted.
.SH PERMISSIONS
When files are checked out of a Git repository, their initial permissions are
dependent upon the user's umask. This can result in confidential files with lax permissions.
To prevent this,
dependent upon the user's umask. Because of this,
.B yadm
will automatically update the permissions of confidential files.
The "group" and "others" permissions will be removed from the following files:
will automatically update the permissions of some file paths. The "group" and
"others" permissions will be removed from the following files:
.RI - " $HOME/.yadm/files.gpg
@ -629,11 +635,32 @@ The "group" and "others" permissions will be removed from the following files:
.B yadm
will automatically update permissions by default. This can be disabled using the
.I yadm.auto-perms
configuration.
Even if disabled, permissions can be manually updated by running
configuration. Even if disabled, permissions can be manually updated by running
.BR yadm\ perms .
The SSH directory processing can be disabled using the
The
.I .ssh
directory processing can be disabled using the
.I yadm.ssh-perms
configuration. The
.I .gnupg
directory processing can be disabled using the
.I yadm.gpg-perms
configuration.
When cloning a repo which includes data in a
.IR .ssh " or " .gnupg
directory, if those directories do not exist at the time of cloning,
.B yadm
will create the directories with mask 0700 prior to merging the fetched data
into the work-tree.
When running a Git command and
.IR .ssh " or " .gnupg
directories do not exist,
.B yadm
will create those directories with mask 0700 prior to running the Git command.
This can be disabled using the
.I yadm.auto-private-dirs
configuration.
.SH HOOKS
For every command

35
yadm.md
View File

@ -214,6 +214,10 @@
manually to update permissions. This feature is enabled by
default.
yadm.auto-private-dirs
Disable the automatic creating of private directories described
in the section PERMISSIONS.
yadm.ssh-perms
Disable the permission changes to $HOME/.ssh/*. This feature is
enabled by default.
@ -405,6 +409,12 @@
.ssh/*.key
.gnupg/*.gpg
Standard filename expansions (*, ?, [) are supported. Other shell
expansions like brace and tilde are not supported. Spaces in paths are
supported, and should not be quoted. If a directory is specified, its
contents will be included, but not recursively. Paths beginning with a
"!" will be excluded.
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-
@ -423,12 +433,9 @@
## PERMISSIONS
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
from the following files:
sions are dependent upon the user's umask. Because of this, yadm will
automatically update the permissions of some file paths. The "group"
and "others" permissions will be removed from the following files:
- $HOME/.yadm/files.gpg
@ -440,8 +447,20 @@
yadm will automatically update permissions by default. This can be dis-
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.
missions can be manually updated by running yadm perms. The .ssh
directory processing can be disabled using the yadm.ssh-perms configu-
ration. The .gnupg directory processing can be disabled using the
yadm.gpg-perms configuration.
When cloning a repo which includes data in a .ssh or .gnupg directory,
if those directories do not exist at the time of cloning, yadm will
create the directories with mask 0700 prior to merging the fetched data
into the work-tree.
When running a Git command and .ssh or .gnupg directories do not exist,
yadm will create those directories with mask 0700 prior to running the
Git command. This can be disabled using the yadm.auto-private-dirs
configuration.
## HOOKS
For every command yadm supports, a program can be provided to run

View File

@ -1,6 +1,6 @@
Summary: Yet Another Dotfiles Manager
Name: yadm
Version: 1.11.0
Version: 1.12.0
Release: 1%{?dist}
URL: https://github.com/TheLocehiliosan/yadm
License: GPLv3
@ -34,10 +34,17 @@ install -m 644 yadm.1 ${RPM_BUILD_ROOT}%{_mandir}/man1
%attr(755,root,root) %{_bindir}/yadm
%attr(644,root,root) %{_mandir}/man1/*
%license LICENSE
%doc CHANGES CONTRIBUTORS README.md completion/yadm.bash_completion
%doc CHANGES CONTRIBUTORS README.md completion/*
%changelog
* Mon July 10 2017 Tim Byrne <sultan@locehilios.com> - 1.11.0-1
* Wed Oct 25 2017 Tim Byrne <sultan@locehilios.com> - 1.12.0-1
- Bump version to 1.12.0
- Include zsh completion
* Wed Aug 23 2017 Tim Byrne <sultan@locehilios.com> - 1.11.1-1
- Bump version to 1.11.1
* Mon Jul 10 2017 Tim Byrne <sultan@locehilios.com> - 1.11.0-1
- Bump version to 1.11.0
* Wed May 10 2017 Tim Byrne <sultan@locehilios.com> - 1.10.0-1