Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
130965e34d
10
CHANGES
10
CHANGES
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
14
Makefile
14
Makefile
|
@ -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
|
||||
|
|
|
@ -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
|
||||
```
|
||||
|
|
|
@ -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 "$@"
|
|
@ -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 ]]
|
||||
}
|
||||
|
|
@ -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[*]}" ]
|
||||
}
|
|
@ -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------"
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
local IFS=$'\n'
|
||||
for matching_file in $(eval ls "$glob" 2>/dev/null); do
|
||||
echo "$matching_file"
|
||||
done
|
||||
if [[ ! $glob =~ ^!(.+) ]] ; then
|
||||
local IFS=$'\n'
|
||||
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
|
||||
|
|
|
@ -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)" {
|
||||
|
|
|
@ -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' ''
|
||||
}
|
||||
|
|
|
@ -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)" {
|
||||
|
|
|
@ -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"
|
||||
}
|
223
yadm
223
yadm
|
@ -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
|
||||
|
@ -841,7 +812,7 @@ function set_operating_system() {
|
|||
CYGWIN*)
|
||||
git_version=$(git --version 2>/dev/null)
|
||||
if [[ "$git_version" =~ windows ]] ; then
|
||||
USE_CYGPATH=1
|
||||
USE_CYGPATH=1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
|
@ -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
45
yadm.1
|
@ -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
|
||||
|
|
157
yadm.md
157
yadm.md
|
@ -214,50 +214,54 @@
|
|||
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.
|
||||
|
||||
yadm.gpg-perms
|
||||
Disable the permission changes to $HOME/.gnupg/*. This feature
|
||||
Disable the permission changes to $HOME/.gnupg/*. This feature
|
||||
is enabled by default.
|
||||
|
||||
yadm.gpg-recipient
|
||||
Asymmetrically encrypt files with a gpg public/private key pair.
|
||||
Provide a "key ID" to specify which public key to encrypt with.
|
||||
The key must exist in your public keyrings. If left blank or
|
||||
not provided, symmetric encryption is used instead. If set to
|
||||
"ASK", gpg will interactively ask for recipients. See the
|
||||
ENCRYPTION section for more details. This feature is disabled
|
||||
Provide a "key ID" to specify which public key to encrypt with.
|
||||
The key must exist in your public keyrings. If left blank or
|
||||
not provided, symmetric encryption is used instead. If set to
|
||||
"ASK", gpg will interactively ask for recipients. See the
|
||||
ENCRYPTION section for more details. This feature is disabled
|
||||
by default.
|
||||
|
||||
yadm.gpg-program
|
||||
Specify an alternate program to use instead of "gpg". By
|
||||
Specify an alternate program to use instead of "gpg". By
|
||||
default, the first "gpg" found in $PATH is used.
|
||||
|
||||
yadm.git-program
|
||||
Specify an alternate program to use instead of "git". By
|
||||
Specify an alternate program to use instead of "git". By
|
||||
default, the first "git" found in $PATH is used.
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
|
@ -268,7 +272,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:
|
||||
|
||||
##
|
||||
|
@ -280,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##
|
||||
|
@ -305,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:
|
||||
|
@ -323,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 <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 <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
|
||||
|
@ -366,7 +370,7 @@
|
|||
YADM_HOSTNAME
|
||||
YADM_USER
|
||||
|
||||
In addition YADM_DISTRO is exposed as the value of lsb_release -si if
|
||||
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
|
||||
|
@ -377,7 +381,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
|
||||
|
@ -390,45 +394,48 @@
|
|||
|
||||
|
||||
## 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
|
||||
|
||||
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-
|
||||
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-
|
||||
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:
|
||||
When files are checked out of a Git repository, their initial permis-
|
||||
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
|
||||
|
||||
|
@ -439,26 +446,38 @@
|
|||
- 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-
|
||||
missions can be manually updated by running yadm perms. The SSH direc-
|
||||
tory processing can be disabled using the yadm.ssh-perms configuration.
|
||||
abled using the yadm.auto-perms configuration. Even if disabled, per-
|
||||
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
|
||||
before or after that command. These are referred to as "hooks". yadm
|
||||
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
|
||||
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-
|
||||
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
|
||||
Hooks have the following environment variables available to them at
|
||||
runtime:
|
||||
|
||||
YADM_HOOK_COMMAND
|
||||
|
@ -477,8 +496,8 @@
|
|||
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
|
||||
|
|
13
yadm.spec
13
yadm.spec
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue