├── .gitignore ├── CHANGELOG.md ├── Makefile ├── README.md ├── dotploy.sh └── tests ├── .gitignore └── test-dotploy.sh /.gitignore: -------------------------------------------------------------------------------- 1 | dotploy 2 | bundles/ 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Version 0.3.4 2 | ------------- 3 | 4 | * More clear nested verbose output 5 | * Full Git HEAD/branch synchronization support 6 | * Add '--vcs-clean' option to clean up VCS database 7 | 8 | Version 0.3.3 9 | ------------- 10 | 11 | * Hotfix: Fix the wrong HEAD file location 12 | 13 | Version 0.3.2 14 | ------------- 15 | 16 | * Standalone version improvements 17 | * Fix checking target deployed from '.__SRC' file 18 | * Symlink to a local path, the existence is irrelevant 19 | 20 | Version 0.3.1 21 | ------------- 22 | 23 | * Doc updates, typo fixes 24 | * Standalone version improvements 25 | 26 | Version 0.3 27 | ----------- 28 | 29 | * New dependency: bashLib 30 | * Use 'make' for building 31 | * Redesigned test structure 32 | * Ability to manage dots repo 33 | * Ability to deploy from VCS or local path 34 | * '$HOME/.dotploy/config' configuration support 35 | * Confilcted files while deploying will be skipped 36 | now, use '--force' option to backup first 37 | 38 | Version 0.2 39 | ----------- 40 | 41 | * Plenty of bugfixes 42 | * Remove command line option '-d' 43 | * Remove command line option '-p' 44 | * Add GUN-style long command line options support 45 | * Show processing details only when '-v' is given 46 | * Backups now is stored in '.dotploy/' directory under 47 | deployment destination 48 | 49 | Version 0.1 50 | ----------- 51 | 52 | * Host based dot files deployment 53 | * User based dot files deployment 54 | * Dead symlinks checking and cleaning 55 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all 2 | all: bundles/bashLib 3 | 4 | .PHONY: test 5 | test: bundles/bashTest 6 | @prove -v tests/test-dotploy.sh 7 | 8 | .PHONY: dev-test 9 | dev-test: 10 | @prove -v tests/test-dotploy.sh 11 | 12 | .PHONY: clean 13 | clean: 14 | @rm -f dotploy && rm -rf bundles 15 | 16 | .PHONY: standalone 17 | standalone: dotploy 18 | 19 | dotploy: bundles/bashLib 20 | @sed -e '1,/# @@BASHLIB BEGIN@@/d' -e '/# @@BASHLIB END@@/,$$d' bundles/bashLib/src/bashLib > bashLib; \ 21 | awk ' \ 22 | /# @@BASHLIB BEGIN@@/ {system("cat bashLib"); bashlib=1; next} \ 23 | /# @@BASHLIB END@@/ {bashlib=0; next} \ 24 | bashlib {next} \ 25 | {print} \ 26 | ' dotploy.sh > dotploy && rm bashLib; \ 27 | sed -i 's/# \(export STANDALONE=1\)/\1/g' dotploy; \ 28 | sed -i 's/dotploy\.sh/dotploy/g' dotploy; \ 29 | chmod a+x dotploy 30 | 31 | bundles: 32 | @mkdir -p bundles 33 | 34 | bundles/bashLib: bundles FORCE 35 | @if [ -d bundles/bashLib ]; \ 36 | then \ 37 | ( cd bundles/bashLib; git checkout master; git fetch --all --prune; git reset --hard origin/master ); \ 38 | else \ 39 | git clone https://github.com/techlivezheng/bashLib.git bundles/bashLib; \ 40 | fi 41 | 42 | bundles/bashTest: bundles/bashLib FORCE 43 | @if [ -d bundles/bashTest ]; \ 44 | then \ 45 | ( cd bundles/bashTest; git checkout master; git fetch --all --prune; git reset --hard origin/master ); \ 46 | else \ 47 | git clone https://github.com/techlivezheng/bashTest.git bundles/bashTest; \ 48 | fi 49 | 50 | FORCE: 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Dotploy 2 | ======= 3 | 4 | This script is designed for ease of deploying the dot files to `$HOME` directory 5 | for mutiple users on several hosts. 6 | 7 | Common dot files needed to be shared with different users on different hosts 8 | could be placed in the root directory of the dots repo. Host specific dot files 9 | could be placed under `__HOST.$HOSTNAME` directory, and user specific dot files 10 | could be placed under `__USER.$USER` or `__HOST.$HOSTNAME/__USER.$USRE` 11 | direcotry. The file in the specified host or user directory with same name has 12 | higher priority. 13 | 14 | It is also possible to deploy from other places or VCS sources(currently, only 15 | Git is supported). If a file in the dots repo has suffix `.__SRC`, it will be 16 | recognized as a record file which holds the URL to the real target. The URL is 17 | formed by three components as `folder::url#fragment`, and each component is 18 | explained as following: 19 | 20 | folder:: (optional) 21 | Specifies an alternate folder name for downloading the VCS source into. 22 | If absent, dotploy will try to use the best name, usually the repo's 23 | name or the directory name of the repo extracted from URL string. 24 | 25 | url 26 | The URL to the VCS repository. The VCS name must be included in the URL 27 | protocol in order to let dotploy recognize this as a VCS source. If the 28 | protocol does not contain the VCS name, it can be added by prefixing 29 | the URL with vcs+. For example, using a Git repository over HTTPS would 30 | have a source URL in the form: `git+https://....` 31 | 32 | #fragment (optional) 33 | Allows specifying tag/branch/revision to checkout from the VCS, or the 34 | relative path of a file from the VCS to be linked to. 35 | 36 | For example, link to a specified file in a given revision, the format 37 | would be `url#revision=123&file=a/b/c`. 38 | 39 | The available fragments depends on the VCS being used. 40 | 41 | Common: 42 | 43 | file - relative path to a file in the VCS repository 44 | 45 | For Git: 46 | 47 | tag - Git tag to checkout 48 | branch - Git branch to checkout 49 | commit - Git commit to checkout 50 | 51 | The VCS source will be downloaded to `.dotploy/vcs` under your deploymet 52 | destination. 53 | 54 | Developed and distributed under GPLv2 or later version. 55 | 56 | How To Use it? 57 | -------------- 58 | 59 | Usage: 60 | 61 | dotploy.sh add [--user] [--host] [--force] [] 62 | 63 | Add to the dots repo and link it back. Be aware that 64 | must be in . 65 | 66 | dotploy.sh remove [] 67 | 68 | Remove the link of to the dots repo, and copy the original 69 | file back. Be aware that must be in . 70 | 71 | dotploy.sh deploy [--force] [] 72 | 73 | Deploy the dots repo the the destination 74 | 75 | Options: 76 | 77 | -h, show help information 78 | -v, be verbose about the process 79 | --user, 80 | add to the `__USER.$USER` directory 81 | --host, 82 | add to the `__HOST.$HOST` directory 83 | --user --host, 84 | add to the `__HOST.$HOST/__USER.$USER` directory 85 | --force, 86 | for 'add' action, if the file exists in dots repo, enabling this 87 | option will overwrite it; 88 | for 'deploy' action, if the file exists in deployment destination, 89 | enabling this option will backup the existing file first. 90 | 91 | If variable `DOTSHOME` has been configured in `$HOME/.dotploy/config`, then 92 | argument `` is optional. 93 | 94 | The argument `` is optional. If it is absent, 95 | the `DESTHOME` variable configured in file `$HOME/.dotploy/config` will be 96 | used. If both of them are undefined, then current `$HOME` directory will be 97 | used. 98 | 99 | Conflicted files will be backed up into `.dotploy/` directory under your 100 | deployment destination. 101 | 102 | Dot Fils Repo Structure 103 | ---------------------- 104 | 105 | The dot files repo structure must be keepd as the same as they are in the 106 | original location. 107 | 108 | DOTFILES_REPO 109 | | 110 | |--------__UNUSED 111 | | ^^^^^^^^ 112 | | This directory is not in use, in which I intend 113 | | to place some dot files that are nolonger used, 114 | | but might be needed someday. 115 | | 116 | |--------__DOTDIR 117 | | | 118 | | |--------.dotfile.__SRC 119 | | | ^^^^^^^^^^^^^^ 120 | | | Deploy from the location decribed in this file. 121 | | | 122 | | |--------.dotdir1 123 | | | | 124 | | | |--------__KEEPED 125 | | | | ^^^^^^^^ 126 | | | | This means this directory shoulde not be 127 | | | | symlinked, instead, deploy its contents 128 | | | | to the corresponding location under the 129 | | | | destination. 130 | | | 131 | | |--------.dotdir2 132 | | | 133 | | |--------...... 134 | | | 135 | | |--------.dotfile1 136 | | | 137 | | |--------.dotfile2 138 | | | 139 | | |--------...... 140 | | | 141 | | |--------__USER.$USER 142 | | | | 143 | | | |--------.dotdir1 144 | | | | | 145 | | | | |--------__KEEPED 146 | | | | 147 | | | |--------.dotdir2 148 | | | | 149 | | | |--------...... 150 | | | | 151 | | | |--------.dotfile1 152 | | | | 153 | | | |--------.dotfile2 154 | | | | 155 | | | |--------...... 156 | | | 157 | | |--------__HOST.$HOSTNAME 158 | | | | 159 | | | |--------__USER.$USER 160 | | | | | 161 | | | | |--------.dotdir1 162 | | | | | | 163 | | | | | |--------__KEEPED 164 | | | | | 165 | | | | |--------.dotdir2 166 | | | | | 167 | | | | |--------...... 168 | | | | | 169 | | | | |--------.dotfile1 170 | | | | | 171 | | | | |--------.dotfile2 172 | | | | | 173 | | | | |--------...... 174 | | | | 175 | | | | 176 | | | |--------.dotdir1 177 | | | | | 178 | | | | |--------__KEEPED 179 | | | | 180 | | | |--------.dotdir2 181 | | | | 182 | | | |--------...... 183 | | | | 184 | | | |--------.dotfile1 185 | | | | 186 | | | |--------.dotfile2 187 | | | | 188 | | | |--------...... 189 | | 190 | |--------.dotfile1 191 | | 192 | |--------.dotfile2 193 | | 194 | |--------...... 195 | | 196 | |--------.dotdir1 197 | | | 198 | | |--------__KEEPED 199 | | 200 | |--------.dotdir2 201 | | 202 | |--------...... 203 | 204 | Copyright 205 | --------- 206 | 207 | Techlive Zheng [techlivezheng at gmail.com] 2012 208 | 209 | 210 | [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/techlivezheng/dotploy/trend.png)](https://bitdeli.com/free "Bitdeli Badge") 211 | 212 | -------------------------------------------------------------------------------- /dotploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # File: dotploy.sh 4 | # 5 | # Author: Techlive Zheng 6 | # 7 | ################################################################################# 8 | # 9 | # Copyright (C) 2012 Free Software Foundation. 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation; either version 2 of the License, or 14 | # (at your option) any later version. 15 | # 16 | # This program is distributed in the hope that it will be useful, 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | # GNU General Public License for more details. 20 | # 21 | # You should have received a copy of the GNU General Public License 22 | # along with this program; if not, write to the Free Software 23 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 24 | # 25 | ################################################################################# 26 | 27 | # @@BASHLIB BEGIN@@ 28 | 29 | # Function: _abspath 30 | # 31 | # Get the absolute path for a file 32 | # 33 | # From: http://stackoverflow.com/questions/59895 34 | # 35 | _abspath() { 36 | local path=${1:-$(caller | cut -d' ' -f2)} 37 | local path_dir=$( dirname "$path" ) 38 | while [[ -h "$path" ]] 39 | do 40 | path=$(readlink "$path") 41 | [[ $path != /* ]] && path=$path_dir/$path 42 | path_dir=$( cd -P "$( dirname "$path" )" && pwd ) 43 | done 44 | path_dir=$( cd -P "$( dirname "$path" )" && pwd ) 45 | echo "$path_dir" 46 | } 47 | 48 | ABSPATH=$(_abspath) 49 | 50 | if [[ -f $ABSPATH/../../libs/bashLib/src/bashLib ]] 51 | then 52 | source "$ABSPATH/../../libs/bashLib/src/bashLib" 53 | elif [[ -f $ABSPATH/bundles/bashLib/src/bashLib ]] 54 | then 55 | source "$ABSPATH/bundles/bashLib/src/bashLib" 56 | elif [[ -f /usr/share/dotploy/bundles/bashLib/bashLib ]] 57 | then 58 | source "/usr/share/dotploy/bundles/bashLib/bashLib" 59 | elif [[ -f /usr/share/lib/bashLib/bashLib ]] 60 | then 61 | source "/usr/share/lib/bashLib/bashLib" 62 | else 63 | echo "Can not find bashLib, you need to install it as bundles first." 64 | exit 1 65 | fi 66 | 67 | # @@BASHLIB END@@ 68 | 69 | ############################################################################### 70 | # 71 | # Git Wrappers 72 | # 73 | ############################################################################### 74 | 75 | _git_is_ref_valid() { 76 | local ref=${1:-ref not set} 77 | git show-ref --verify --quiet $ref 78 | } 79 | 80 | _git_has_local_change() { 81 | ! git diff-index --quiet --exit-code HEAD 82 | } 83 | 84 | _git_is_head_detached() { 85 | ! git symbolic-ref HEAD &>/dev/null 86 | } 87 | 88 | _git_is_ref_in_remote() { 89 | local ref=${1:?ref not set} 90 | [[ -n "$(git branch -r --contains $ref)" ]] 91 | } 92 | 93 | _git_is_head_in_remote() { 94 | _git_is_ref_in_remote HEAD 95 | } 96 | 97 | _git_is_head_tracking_remote() { 98 | git rev-parse --abbrev-ref @{u} &>/dev/null 99 | } 100 | 101 | ############################################################################### 102 | # 103 | # Main Program 104 | # 105 | ############################################################################### 106 | 107 | ABSPATH=$(_abspath) 108 | 109 | IFS=$'\n' 110 | 111 | # get real user name 112 | USER=$(id -nu) 113 | 114 | [[ -z $USER ]] && die "Unkown user" 115 | 116 | # get current host name 117 | HOST=$HOSTNAME 118 | 119 | [[ -z $HOST ]] && die "Unkown host" 120 | 121 | # preserved files 122 | IGNORE=( 123 | "^__USER" 124 | "^__HOST" 125 | "^__KEEPED" 126 | "^__IGNORE" 127 | "^.git$" 128 | ".swp$" 129 | ) 130 | 131 | print() { 132 | local indent 133 | if [[ $DEPTH -gt 1 ]] 134 | then 135 | indent=$(printf '\t%.0s' $(seq 1 $(($DEPTH -1)))) 136 | fi 137 | [[ $OPT_VERBOSE -eq 1 ]] && [[ -n "$1" ]] && echo "$1" | sed "s/^/$indent/g" 138 | } 139 | 140 | printe() ( 141 | exec 1>&2 142 | [[ $OPT_VERBOSE -eq 1 ]] && { 143 | [[ -n "$1" ]] && print "ERROR: $1" 144 | } || { 145 | [[ -n "$1" ]] && echo "ERROR: $1" 146 | } 147 | ) 148 | 149 | printw() ( 150 | exec 1>&2 151 | [[ $OPT_VERBOSE -eq 1 ]] && { 152 | [[ -n "$1" ]] && print "Warning: $1" 153 | } || { 154 | [[ -n "$1" ]] && echo "Warning: $1" 155 | } 156 | ) 157 | 158 | # Abtain the record to the source 159 | get_src() { 160 | head -1 $1 161 | } 162 | 163 | # Directory to store the VCS source 164 | get_dir() { 165 | mkdir -p $CONFDIR/vcs/ 166 | 167 | echo $CONFDIR/vcs/$(get_filename "$(get_src "$1")")$(basename "$1" | sed 's/.__SRC$//g') 168 | } 169 | 170 | # extract the URL from a source entry 171 | get_url() { 172 | # strip an eventual filename 173 | printf "%s\n" "${1#*::}" 174 | } 175 | 176 | # extract the protocol from a source entry - return "local" for local sources 177 | get_protocol() { 178 | if [[ $1 = *://* ]] 179 | then 180 | # strip leading filename 181 | local proto="${1##*::}" 182 | printf "%s\n" "${proto%%://*}" 183 | else 184 | printf "%s\n" local 185 | fi 186 | } 187 | 188 | # extract the filename from a source entry 189 | get_filename() { 190 | local src=$1 191 | 192 | # if a filename is specified, use it 193 | if [[ $src = *::* ]] 194 | then 195 | printf "%s\n" ${src%%::*} 196 | return 197 | fi 198 | 199 | local proto=$(get_protocol "$src") 200 | case $proto in 201 | git*) 202 | filename=${src%%#*} 203 | filename=${filename%/} 204 | filename=${filename##*/} 205 | if [[ $proto = git* ]] 206 | then 207 | filename=${filename%%.git*} 208 | fi 209 | ;; 210 | *) 211 | # if it is just an URL, we only keep the last component 212 | filename="${src##*/}" 213 | ;; 214 | esac 215 | printf "%s\n" "${filename}" 216 | } 217 | 218 | # Return the absolute filename of a source entry 219 | get_filepath() { 220 | local src=$(get_src "$1") 221 | 222 | local file=$(get_fragment "$src" "file") 223 | local proto=$(get_protocol "$src") 224 | case "$proto" in 225 | git*) 226 | if [[ -n $file ]] 227 | then 228 | echo $(get_dir "$1")/$file 229 | else 230 | echo $(get_dir "$1") 231 | fi 232 | ;; 233 | local) 234 | echo $(get_url "$src") 235 | ;; 236 | esac 237 | } 238 | 239 | get_fragment() { 240 | local url=$1 241 | local target=$2 242 | local fragment=${url#*#} 243 | 244 | if [[ $fragment = "$url" ]] 245 | then 246 | return 247 | fi 248 | 249 | if [[ -n $fragment ]] 250 | then 251 | if [[ $target = ref ]] 252 | then 253 | if [[ $fragment =~ tag=* ]] 254 | then 255 | echo $fragment | sed 's/.*tag=\([^&]*\).*/\1/g;s|^refs/tags/||;s|^|refs/tags/|' 256 | elif [[ $fragment =~ branch=* ]] 257 | then 258 | echo $fragment | sed 's/.*branch=\([^&]*\).*/\1/g;s|^refs/heads/||;s|^refs/remotes/origin/||;s|^|refs/remotes/origin/|' 259 | elif [[ $fragment =~ commit=* ]] 260 | then 261 | echo $fragment | sed 's/.*commit=\([^&]*\).*/\1/g' 262 | fi 263 | elif [[ $target = file ]] 264 | then 265 | if [[ $fragment =~ file=* ]] 266 | then 267 | echo $fragment | sed 's/.*file=\([^&]*\).*/\1/g' 268 | fi 269 | fi 270 | fi 271 | } 272 | 273 | ensure_source() { 274 | local src=$(get_src "$1") 275 | 276 | local proto=$(get_protocol "$src") 277 | case "$proto" in 278 | git*) 279 | ensure_source_git "$1" 280 | ;; 281 | local) 282 | ensure_source_local "$1" 283 | ;; 284 | *) 285 | printe "Unkown protocol $proto ..." 286 | exit 1 287 | ;; 288 | esac 289 | } 290 | 291 | ensure_source_git() ( 292 | local src=$(get_src "$1") 293 | 294 | mkdir -p $CONFDIR/vcs/ 295 | 296 | local dir=$(get_dir "$1") 297 | local url=$(get_url "$src") 298 | url=${url##*git+} 299 | url=${url##*file:\/\/} 300 | url=${url%%#*} 301 | 302 | # Fetch the remote update if we have it cloned already and the upstream is correct 303 | if [[ -d "$dir/.git" ]] && ( _cd "$dir" && [[ "$url" == "$(git config --get remote.origin.url)" ]] ) 304 | then 305 | if ( _cd "$dir" && ! git fetch --all --prune --quiet ) 306 | then 307 | printw "Failed to fetch upstream '$url' in '$dir'." 308 | else 309 | ( _cd "$dir" && git remote set-head origin -a &>/dev/null ) 310 | fi 311 | # Otherwise, backup and remove any existed invalid file/directory occupied the target 312 | # location before the clone 313 | else 314 | if [[ -e "$dir" ]] && { [[ ! -d "$dir" ]] || { [[ -d "$dir" ]] && ! _is_dir_empty "$dir"; }; } 315 | then 316 | printw "'$dir' is already there, backup to '$BAKPATH'." 317 | mkdir -p $BAKPATH && mv $dir $BAKPATH 318 | fi 319 | 320 | if ! git clone --quiet "$url" "$dir" 321 | then 322 | printe "Failed to clone repository '$url' to '$dir'." 323 | exit 1 324 | fi 325 | fi 326 | 327 | _cd "$dir" 328 | 329 | local ref=$(get_fragment "$src" "ref") 330 | if [[ -z $ref ]] || { ! _git_is_ref_valid $ref && ! _git_is_ref_in_remote $ref && printw "$ref is not a valid git ref, use HEAD of origin."; } 331 | then 332 | #keep the head in sync with the remote 333 | ref=refs/remotes/origin/HEAD 334 | fi 335 | 336 | if [[ $(git rev-parse HEAD) != $(git rev-parse $ref) ]] 337 | then 338 | if _git_has_local_change || { _git_is_head_detached && ! _git_is_head_in_remote; } || { _git_is_head_tracking_remote && ! _git_is_head_in_remote; } 339 | then 340 | printw "Our clone of the repository $(pwd) has local changes, abort further operation, please resolve first." 341 | else 342 | if [[ $ref =~ ^refs/remotes/origin ]] && [[ $ref != refs/remotes/origin/HEAD ]] 343 | then 344 | if ! { git checkout --quiet ${ref##refs/remotes/origin/} && git reset --hard --quiet $ref; } 345 | then 346 | printw "Unable to keep the branch in sync with upstream" 347 | fi 348 | else 349 | if ! git checkout --quiet $ref 350 | then 351 | if [[ $ref == "refs/remotes/origin/HEAD" ]] 352 | then 353 | printw "Unable to keep HEAD in sync with remote" 354 | else 355 | printw "Unable to checkout requested reference" 356 | fi 357 | fi 358 | fi 359 | fi 360 | fi 361 | 362 | if [[ $OPT_VCS_CLEAN == 1 ]] 363 | then 364 | # clean dangling objects 365 | git reflog expire --expire=now --all 366 | 367 | # clean safe-keeping references 368 | refbak=$(git for-each-ref --format="%(refname)" refs/original/) 369 | if [ -n "$refbak" ] 370 | then 371 | echo -n $refbak | xargs -n 1 git update-ref -d 372 | fi 373 | 374 | # show git database status 375 | git fsck 376 | 377 | # repack git database objects 378 | git repack -a -d 379 | 380 | # collect garbage 381 | git gc --prune=now --aggresive 382 | fi 383 | ) 384 | 385 | ensure_source_local() ( 386 | local src=$(get_src "$1") 387 | local url=$(get_url "$src") 388 | 389 | true 390 | ) 391 | 392 | # 393 | # Function: _prune 394 | # 395 | # Remove broken symlinks 396 | # 397 | # Parameters: 398 | # $1 log file recorded the deployed symlinks 399 | # 400 | _prune() { 401 | local logfile=$1 402 | 403 | local file 404 | for file in $(cat $logfile); do 405 | _check $file 406 | 407 | [[ $? -eq 1 ]] && { 408 | DEPTH=$(( $DEPTH + 1 )) 409 | print 'UPDATE:'$'\t'"$file" 410 | DEPTH=$(( $DEPTH + 1 )) 411 | print "$(rm -v $file)" 412 | DEPTH=$(( $DEPTH - 1 )) 413 | DEPTH=$(( $DEPTH - 1 )) 414 | } 415 | done 416 | } 417 | 418 | # 419 | # Function: _check 420 | # 421 | # Check the status of a given file 422 | # 423 | # Parameters: 424 | # $1 target file to be checked 425 | # 426 | # Return Value: 427 | # 0 all good 428 | # 1 need update 429 | # 2 need backup 430 | # 3 not existed, do link 431 | # 4 do nothing, deploy its contents 432 | # 433 | _check() { 434 | local src 435 | local dst=$1 436 | local repath 437 | 438 | repath=${dst#$DESTHOME} 439 | repath=${repath#/} 440 | 441 | [[ -e $DOTSREPO/$repath ]] && src=$DOTSREPO/$repath 442 | [[ -e $DOTSREPO/$repath.__SRC ]] && src=$DOTSREPO/$repath.__SRC 443 | [[ -e $DOTSREPO/__USER.$USER/$repath ]] && src=$DOTSREPO/__USER.$USER/$repath 444 | [[ -e $DOTSREPO/__USER.$USER/$repath.__SRC ]] && src=$DOTSREPO/__USER.$USER/$repath.__SRC 445 | [[ -e $DOTSREPO/__HOST.$HOST/$repath ]] && src=$DOTSREPO/__HOST.$HOST/$repath 446 | [[ -e $DOTSREPO/__HOST.$HOST/$repath.__SRC ]] && src=$DOTSREPO/__HOST.$HOST/$repath.__SRC 447 | [[ -e $DOTSREPO/__HOST.$HOST/__USER.$USER/$repath ]] && src=$DOTSREPO/__HOST.$HOST/__USER.$USER/$repath 448 | [[ -e $DOTSREPO/__HOST.$HOST/__USER.$USER/$repath.__SRC ]] && src=$DOTSREPO/__HOST.$HOST/__USER.$USER/$repath.__SRC 449 | 450 | if [[ -h $dst ]] 451 | then 452 | local csrc=$(readlink $dst) 453 | 454 | if [[ "$csrc" == "$src" ]] 455 | then 456 | return 0 457 | elif [[ $src =~ .*\.__SRC ]] && [[ $csrc == $(get_filepath "$src") ]] 458 | then 459 | return 0 460 | else 461 | if [[ $csrc =~ $DOTSHOME ]] 462 | then 463 | return 1 464 | else 465 | return 2 466 | fi 467 | fi 468 | elif [[ -d $dst ]] 469 | then 470 | if [[ -f $src/__KEEPED ]] 471 | then 472 | return 4 473 | else 474 | return 2 475 | fi 476 | elif [[ -f $dst ]] 477 | then 478 | return 2 479 | else 480 | return 3 481 | fi 482 | } 483 | 484 | # 485 | # Function: _deploy 486 | # 487 | # Deploy files 488 | # 489 | # Parameters: 490 | # $1 directory containing dot files 491 | # $2 directory where files need to go 492 | # 493 | # This function can be called recursively. 494 | # 495 | _deploy() { 496 | local dotdir=$1 497 | local dstdir=$2 498 | 499 | DEPTH=$(( $DEPTH + 1 )) 500 | print 'ENTER:'$'\t'"$dotdir" 501 | 502 | local filelist=$(ls -1A --color=none $dotdir) 503 | 504 | local file 505 | for file in $filelist; do 506 | # skip preserved filenames 507 | local line 508 | for line in ${IGNORE[@]};do 509 | [[ $file =~ $line ]] && continue 2 510 | done 511 | 512 | # apply user-defined ignoring rules 513 | if [[ -f $dotdir/__IGNORE ]] 514 | then 515 | local line 516 | for line in $(cat $dotdir/__IGNORE);do 517 | [[ $file =~ $line ]] && continue 2 518 | done 519 | fi 520 | 521 | if [[ -d $dotdir/$file ]] 522 | then 523 | if [[ -e $dotdir/$file/__KEEPED ]] 524 | then 525 | # this directory needs to be kept, 526 | # deploy its contents. 527 | _deploy $dotdir/$file $dstdir/$file 528 | else 529 | _symlink $dotdir $dstdir $file 530 | fi 531 | elif [[ -f $dotdir/$file ]] 532 | then 533 | _symlink $dotdir $dstdir $file 534 | fi 535 | 536 | grep "^$dstdir/$file\$" $LOGFILE >/dev/null 2>&1 537 | 538 | [[ $? -ne 0 ]] && echo "$dstdir/$file" >> $LOGFILE 539 | done 540 | 541 | print 'LEAVE:'$'\t'"$dotdir" 542 | DEPTH=$(( $DEPTH - 1 )) 543 | } 544 | 545 | # 546 | # Function: _symlink 547 | # 548 | # Make a symlink. 549 | # 550 | # If the target file exists, backup it first. 551 | # 552 | # Parameters: 553 | # $1 source directory where the dotfile is located 554 | # $2 target directory where the dotfile will be deployed 555 | # $3 filename of the dotfile 556 | # 557 | _symlink() { 558 | local src 559 | local dst 560 | 561 | [[ $3 =~ ^.*.__SRC$ ]] && { 562 | ensure_source "$1/$3" || return 563 | src=$(get_filepath "$1/$3") 564 | dst=${2%%/}/${3%%.__SRC} 565 | } || { 566 | src=${1%%/}/$3 567 | dst=${2%%/}/$3 568 | } 569 | 570 | local repath 571 | 572 | repath=${1#$DOTSREPO} 573 | repath=${repath#/} 574 | repath=${repath#__HOST.$HOST} 575 | repath=${repath#/} 576 | repath=${repath#__USER.$USER} 577 | repath=${repath#/} 578 | 579 | # for nested path, need to mkdir parent first 580 | [[ -n "$repath" ]] && { 581 | # backup if the target already exits 582 | [[ -f "$DESTHOME/$repath" ]] && { 583 | DEPTH=$(( $DEPTH + 1 )) 584 | print 'BACKUP:'$'\t'"$DESTHOME/$repath" 585 | DEPTH=$(( $DEPTH + 1 )) 586 | print "$(mkdir -vp $BAKPATH/$(dirname "$repath") && mv -v $DESTHOME/$repath $BAKPATH/$(dirname "$repath"))" 587 | DEPTH=$(( $DEPTH - 1 )) 588 | DEPTH=$(( $DEPTH - 1 )) 589 | } 590 | DEPTH=$(( $DEPTH + 1 )) 591 | print $'MKDIR:\t'"$DESTHOME/$repath" 592 | DEPTH=$(( $DEPTH + 1 )) 593 | print "$(mkdir -vp $DESTHOME/$repath)" 594 | DEPTH=$(( $DEPTH - 1 )) 595 | DEPTH=$(( $DEPTH - 1 )) 596 | } 597 | 598 | _check $dst 599 | 600 | local status=$? 601 | 602 | # remove broken link 603 | [[ $status -eq 1 ]] && { 604 | DEPTH=$(( $DEPTH + 1 )) 605 | print 'REMOVE:'$'\t'"$dst" 606 | DEPTH=$(( $DEPTH + 1 )) 607 | print "$(rm -v $dst)" 608 | DEPTH=$(( $DEPTH - 1 )) 609 | DEPTH=$(( $DEPTH - 1 )) 610 | } 611 | 612 | # backup existed file 613 | [[ $status -eq 2 ]] && { 614 | [[ $OPT_FORCE = 1 ]] && { 615 | DEPTH=$(( $DEPTH + 1 )) 616 | print 'BACKUP:'$'\t'"$dst" 617 | DEPTH=$(( $DEPTH + 1 )) 618 | print "$(mkdir -vp $BAKPATH/$repath && mv -v $dst $BAKPATH/$repath)" 619 | DEPTH=$(( $DEPTH - 1 )) 620 | DEPTH=$(( $DEPTH - 1 )) 621 | } || { 622 | printw "$dst already exists, use --force option to force deploying" 623 | return 624 | } 625 | } 626 | 627 | # symlink the file in the repo 628 | [[ $status -ne 0 ]] && [[ $status -ne 4 ]] && { 629 | DEPTH=$(( $DEPTH + 1 )) 630 | print 'LINK:'$'\t'"$dst" 631 | DEPTH=$(( $DEPTH + 1 )) 632 | print "$(ln -v -s $src $dst)" 633 | DEPTH=$(( $DEPTH - 1 )) 634 | DEPTH=$(( $DEPTH - 1 )) 635 | } 636 | } 637 | 638 | doadd() { 639 | #check if our target is in the desthome 640 | [[ $TARGET =~ $DESTHOME/.* ]] || die "target not in dest home" 641 | 642 | local rpath=${TARGET##$DESTHOME/} 643 | 644 | local dest 645 | if [[ $OPT_HOST == 0 ]] && [[ $OPT_USER == 0 ]] 646 | then 647 | dest=$DOTSREPO 648 | elif [[ $OPT_HOST == 1 ]] && [[ $OPT_USER == 0 ]] 649 | then 650 | dest=$DOTSREPO/__HOST.$HOST 651 | elif [[ $OPT_HOST == 0 ]] && [[ $OPT_USER == 1 ]] 652 | then 653 | dest=$DOTSREPO/__USER.$USER 654 | elif [[ $OPT_HOST == 1 ]] && [[ $OPT_USER == 1 ]] 655 | then 656 | dest=$DOTSREPO/__HOST.$HOST/__USER.$USER 657 | fi 658 | 659 | #check if the target already in the destination 660 | [[ -e $dest/$rpath ]] && [[ $OPT_FORCE == 0 ]] && { 661 | die "target already exists" 662 | } 663 | 664 | local file=$(basename $rpath) 665 | 666 | #move the target to the destination 667 | mkdir -p "$dest/${rpath%%$file}" 668 | mv "$TARGET" "$dest/${rpath%%$file}" 669 | 670 | [[ $rpath == $file ]] || { 671 | touch "$dest/${rpath%%$file}/__KEEPED" 672 | } 673 | 674 | #link the target back 675 | _symlink "$dest/${rpath%%$file}" "${TARGET%%$file}" $file 676 | } 677 | 678 | doremove() { 679 | #check if our target is a real link 680 | [[ -h $TARGET ]] || die "target is not a link" 681 | 682 | #check if our target is in the desthome 683 | [[ $TARGET =~ $DESTHOME/.* ]] || die "target not in dest home" 684 | 685 | #check if our target is linking to our dots repo 686 | [[ $(readlink -fm $TARGET) =~ $DOTSREPO/.* ]] || die "target not link to our repo" 687 | 688 | #remove the link and copy the original file 689 | local from=$(readlink -fm $TARGET) 690 | local to=$(dirname $TARGET) 691 | rm $TARGET && cp -rf $from $to 692 | } 693 | 694 | dodeploy() { 695 | CONFDIR=$DESTHOME/.dotploy 696 | 697 | mkdir -p $CONFDIR || exit 1 698 | 699 | # backup location, categarized by date 700 | BAKPATH=$CONFDIR/backup/`date +%Y%m%d.%H.%M.%S` 701 | 702 | # keep a record of the deployed files 703 | LOGFILE=$CONFDIR/filelog 704 | 705 | # transform old backup sctruction to the new one 706 | [[ -d $DOTSHOME/__BACKUP/$HOST ]] && { 707 | echo "Performing transition ..." 708 | 709 | [[ -f $LOGFILE ]] && mv $LOGFILE $LOGFILE.bak 710 | for bakpath in $(grep -l "^$DESTHOME\$" $DOTSHOME/__BACKUP/$HOST/*/DESTHOME | sed 's-/DESTHOME$--g');do 711 | mv $bakpath/dotploy.log $LOGFILE &>/dev/null 712 | 713 | [[ -f $bakpath/dotploy.log ]] && { 714 | echo error 715 | continue 716 | } 717 | 718 | rm $bakpath/DESTHOME &>/dev/null 719 | 720 | [[ -f $bakpath/DESTHOME ]] && { 721 | echo error 722 | continue 723 | } 724 | 725 | rmdir $bakpath &> /dev/null || mv $bakpath $CONFDIR/backup 726 | done 727 | [[ -f $LOGFILE.bak ]] && mv $LOGFILE.bak $LOGFILE 728 | 729 | rmdir --ignore-fail-on-non-empty -p $DOTSHOME/__BACKUP/$HOST 730 | 731 | echo "Transition done." 732 | } 733 | 734 | if [[ -f $LOGFILE ]] 735 | then 736 | _prune $LOGFILE 737 | fi 738 | 739 | # host user based dotfies deploy 740 | [[ -d $DOTSREPO/__HOST.$HOST/__USER.$USER ]] && \ 741 | _deploy $DOTSREPO/__HOST.$HOST/__USER.$USER $DESTHOME 742 | 743 | # host based dotfies deploy 744 | [[ -d $DOTSREPO/__HOST.$HOST ]] && \ 745 | _deploy $DOTSREPO/__HOST.$HOST $DESTHOME 746 | 747 | # user based dotfies deploy 748 | [[ -d $DOTSREPO/__USER.$USER ]] && \ 749 | _deploy $DOTSREPO/__USER.$USER $DESTHOME 750 | 751 | # shared dotfiles deploy 752 | _deploy $DOTSREPO $DESTHOME 753 | } 754 | 755 | show_help() { 756 | cat << 'EOF' 757 | 758 | Usage: 759 | 760 | dotploy.sh add [--user] [--host] [--force] [] 761 | 762 | add to the dots repo, and link it back 763 | 764 | dotploy.sh remove [] 765 | 766 | Remove the link of to the dots repo, and copy the original file back 767 | 768 | dotploy.sh deploy [--force] [] 769 | 770 | deploy the dots repo the the destination 771 | 772 | Options: 773 | 774 | -h, show help information 775 | -v, be verbose about the process 776 | --user, 777 | add to the `__USER.$USER` directory 778 | --host, 779 | add to the `__HOST.$HOST` directory 780 | --user --host, 781 | add to the `__HOST.$HOST/__USER.$USER` directory 782 | --force, 783 | for 'add' action, if the file exists in dots repo, enabling this 784 | option will overwrite it; 785 | for 'deploy' action, if the file exists in deployment destination, 786 | enabling this option will backup the existing file first. 787 | 788 | The argument `` is optional. If it is absent, 789 | then current `$HOME` directory will be used. 790 | 791 | Conflicted files will be backed up into `.dotploy/` directory under your 792 | deployment destination. 793 | 794 | EOF 795 | } 796 | 797 | declare -a args 798 | declare -i DEPTH=0 799 | declare -i OPT_USER=0 800 | declare -i OPT_HOST=0 801 | declare -i OPT_FORCE=0 802 | declare -i OPT_VERBOSE=0 803 | declare -i OPT_VCS_CLEAN=0 804 | while [[ $# -gt 0 ]] 805 | do 806 | case "$1" in 807 | --user ) 808 | OPT_USER=1 809 | ;; 810 | --host ) 811 | OPT_HOST=1 812 | ;; 813 | --force ) 814 | OPT_FORCE=1 815 | ;; 816 | --vcs-clean ) 817 | OPT_VCS_CLEAN=1 818 | ;; 819 | -p ) 820 | echo "Option '-p' has been depreciated" 821 | show_help 822 | exit 1 823 | ;; 824 | -d ) 825 | echo "Option '-d' has been depreciated" 826 | show_help 827 | exit 1 828 | ;; 829 | -v | --verbose ) 830 | OPT_VERBOSE=1 831 | ;; 832 | -h | --help ) 833 | show_help 834 | exit 0 835 | ;; 836 | -* ) 837 | echo "ERROR: Unknown option $1" 838 | show_help 839 | exit 1 840 | ;; 841 | * ) 842 | args+=("$1") 843 | ;; 844 | esac 845 | shift 846 | done 847 | 848 | set -- "${args[@]}" 849 | 850 | ACTION=$1 851 | case "$ACTION" in 852 | add | remove ) 853 | shift 854 | TARGET=$(realpath --no-symlinks ${1%%\/}) 855 | shift 856 | ;; 857 | deploy ) 858 | shift 859 | ;; 860 | * ) 861 | show_help 862 | exit 1 863 | ;; 864 | esac 865 | 866 | [[ -f "$HOME/.dotploy/config" ]] && source $HOME/.dotploy/config 867 | 868 | DOTSHOME=$(realpath ${1:-$DOTSHOME}) 869 | 870 | # make sure our destination is there 871 | [[ -d $DOTSHOME ]] || die "$DOTSHOME is not available" 872 | 873 | DOTSREPO=$DOTSHOME/__DOTDIR 874 | 875 | # die if it is not a dotsrepo 876 | [[ -d $DOTSREPO ]] || die "$DOTSREPO is not available" 877 | 878 | DESTHOME=$(realpath ${2:-${DESTHOME:-$HOME}}) 879 | 880 | # make sure our destination is there 881 | [[ -d $DESTHOME ]] || die "$DESTHOME is not available" 882 | 883 | do$ACTION 884 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | /test-field/ 2 | -------------------------------------------------------------------------------- /tests/test-dotploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function: _abspath 4 | # 5 | # Get the absolute path for a file 6 | # 7 | # From: http://stackoverflow.com/questions/59895 8 | # 9 | _abspath() { 10 | local path=${1:-$(caller | cut -d' ' -f2)} 11 | local path_dir=$( dirname "$path" ) 12 | while [[ -h "$path" ]] 13 | do 14 | path=$(readlink "$path") 15 | [[ $path != /* ]] && path=$path_dir/$path 16 | path_dir=$( cd -P "$( dirname "$path" )" && pwd ) 17 | done 18 | path_dir=$( cd -P "$( dirname "$path" )" && pwd ) 19 | echo "$path_dir" 20 | } 21 | 22 | ABSPATH=$(_abspath) 23 | 24 | if [[ -f $ABSPATH/../../../libs/bashTest/src/bashTest ]] 25 | then 26 | source "$ABSPATH/../../../libs/bashTest/src/bashTest" 27 | elif [[ -f $ABSPATH/../bundles/bashTest/src/bashTest ]] 28 | then 29 | source "$ABSPATH/../bundles/bashTest/src/bashTest" 30 | elif [[ -f /usr/share/dotploy/bundles/bashTest/bashTest ]] 31 | then 32 | source "/usr/share/dotploy/bundles/bashTest/bashTest" 33 | elif [[ -f /usr/share/lib/bashTest/bashTest ]] 34 | then 35 | source "/usr/share/lib/bashTest/bashTest" 36 | else 37 | echo "Can not find bashTest, you need to install it as bundles first." 38 | exit 1 39 | fi 40 | 41 | ############################################################################### 42 | # 43 | # Test Helpers 44 | # 45 | ############################################################################### 46 | 47 | ABSPATH=$(_abspath) 48 | 49 | _set_up() { 50 | export PATH=$(realpath $ABSPATH/..):$PATH 51 | 52 | export TEST_FIELD=$ABSPATH'/test-field/'$TEST_COUNT 53 | 54 | rm -rf "$TEST_FIELD" || die "Failed to set up test facility." 55 | 56 | mkdir -p "$TEST_FIELD/dotsdest" 57 | mkdir -p "$TEST_FIELD/dotsrepo" 58 | mkdir -p "$TEST_FIELD/dotsrepo/__DOTDIR" 59 | 60 | cd "$TEST_FIELD" 61 | } 62 | 63 | _tear_down() { 64 | true 65 | } 66 | 67 | _make_layer() { 68 | local layer 69 | for layer in "$@";do 70 | mkdir -p "$(_dirname "$layer")" && touch "$layer" 71 | done 72 | } 73 | 74 | ############################################################################### 75 | # 76 | # Git Wrappers 77 | # 78 | ############################################################################### 79 | 80 | _git_tag() ( 81 | exec &>/dev/null 82 | cd test.git 83 | 84 | git tag "$@" 85 | ) 86 | 87 | _git_init() ( 88 | exec &>/dev/null 89 | cd test.git 90 | 91 | git init "$@" 92 | ) 93 | 94 | _git_commit() ( 95 | file=${1:?not set} 96 | data=${2:?not set} 97 | info=${3:?not set} 98 | 99 | exec &>/dev/null 100 | cd test.git 101 | 102 | [[ $1 =~ */ ]] && { 103 | mkdir -p $file 104 | } || { 105 | mkdir -p $(dirname $file) 106 | touch $file 107 | } 108 | echo "$data" >> $file 109 | 110 | git add $file 111 | git commit -m "$info" 112 | ) 113 | 114 | _git_checkout() ( 115 | exec &>/dev/null 116 | cd test.git 117 | 118 | git checkout "$@" 119 | ) 120 | 121 | _git_set_up() ( 122 | mkdir -p "test.git" 123 | _git_init 124 | _git_commit 1 1 1 125 | _git_commit 2 2 2 126 | _git_tag v0.1 127 | _git_commit 3 3 3 128 | _git_checkout -b develop 129 | _git_commit 4 4 4 130 | _git_checkout master 131 | ) 132 | 133 | _git_tear_down() { 134 | rm -rf "test.git" 135 | } 136 | 137 | ############################################################################### 138 | # 139 | # Actual Tests 140 | # 141 | ############################################################################### 142 | 143 | USER=$(id -nu) 144 | HOST=$HOSTNAME 145 | 146 | _test_run "Shared dot files deployment" ' 147 | repo_layer=( 148 | "dotsrepo/__DOTDIR/.dotdir/" 149 | "dotsrepo/__DOTDIR/.dotfile" 150 | ) 151 | _make_layer "${repo_layer[@]}" 152 | dotploy.sh deploy "dotsrepo" "dotsdest" 153 | _test_expect_symlink "dotsdest/.dotdir" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotdir" 154 | _test_expect_symlink "dotsdest/.dotfile" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotfile" 155 | ' 156 | 157 | _test_run "User based dot files deployment" ' 158 | repo_layer=( 159 | "dotsrepo/__DOTDIR/.dotdir/" 160 | "dotsrepo/__DOTDIR/.dotfile" 161 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir/" 162 | "dotsrepo/__DOTDIR/__USER.$USER/.dotfile" 163 | ) 164 | _make_layer "${repo_layer[@]}" 165 | dotploy.sh deploy "dotsrepo" "dotsdest" 166 | _test_expect_symlink "dotsdest/.dotdir" "$TEST_FIELD/dotsrepo/__DOTDIR/__USER.$USER/.dotdir" 167 | _test_expect_symlink "dotsdest/.dotfile" "$TEST_FIELD/dotsrepo/__DOTDIR/__USER.$USER/.dotfile" 168 | ' 169 | 170 | _test_run "Host based dot files deployment" ' 171 | repo_layer=( 172 | "dotsrepo/__DOTDIR/.dotdir/" 173 | "dotsrepo/__DOTDIR/.dotfile" 174 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir/" 175 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotfile" 176 | ) 177 | _make_layer "${repo_layer[@]}" 178 | dotploy.sh deploy "dotsrepo" "dotsdest" 179 | _test_expect_symlink "dotsdest/.dotdir" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir" 180 | _test_expect_symlink "dotsdest/.dotfile" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotfile" 181 | ' 182 | 183 | _test_run "Host based dot files deployment with user based exits" ' 184 | repo_layer=( 185 | "dotsrepo/__DOTDIR/.dotdir/" 186 | "dotsrepo/__DOTDIR/.dotfile" 187 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir/" 188 | "dotsrepo/__DOTDIR/__USER.$USER/.dotfile" 189 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir/" 190 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotfile" 191 | ) 192 | _make_layer "${repo_layer[@]}" 193 | dotploy.sh deploy "dotsrepo" "dotsdest" 194 | _test_expect_symlink "dotsdest/.dotdir" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir" 195 | _test_expect_symlink "dotsdest/.dotfile" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotfile" 196 | ' 197 | 198 | _test_run "Host then user based dot file deployment" ' 199 | repo_layer=( 200 | "dotsrepo/__DOTDIR/.dotdir/" 201 | "dotsrepo/__DOTDIR/.dotfile" 202 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir/" 203 | "dotsrepo/__DOTDIR/__USER.$USER/.dotfile" 204 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir/" 205 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotfile" 206 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir/" 207 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotfile" 208 | ) 209 | _make_layer "${repo_layer[@]}" 210 | dotploy.sh deploy "dotsrepo" "dotsdest" 211 | _test_expect_symlink "dotsdest/.dotdir" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir" 212 | _test_expect_symlink "dotsdest/.dotfile" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotfile" 213 | ' 214 | 215 | _test_run "Fallback host based to shared" ' 216 | repo_layer=( 217 | "dotsrepo/__DOTDIR/.dotdir/" 218 | "dotsrepo/__DOTDIR/.dotfile" 219 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir/" 220 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotfile" 221 | ) 222 | _make_layer "${repo_layer[@]}" 223 | dotploy.sh deploy "dotsrepo" "dotsdest" 224 | rm "dotsrepo/__DOTDIR/__HOST.$HOST/.dotfile" 225 | rmdir "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir/" 226 | dotploy.sh deploy "dotsrepo" "dotsdest" 227 | _test_expect_symlink "dotsdest/.dotdir" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotdir" 228 | _test_expect_symlink "dotsdest/.dotfile" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotfile" 229 | ' 230 | 231 | _test_run "Fallback user based to shared" ' 232 | repo_layer=( 233 | "dotsrepo/__DOTDIR/.dotdir/" 234 | "dotsrepo/__DOTDIR/.dotfile" 235 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir/" 236 | "dotsrepo/__DOTDIR/__USER.$USER/.dotfile" 237 | ) 238 | _make_layer "${repo_layer[@]}" 239 | dotploy.sh deploy "dotsrepo" "dotsdest" 240 | rm "dotsrepo/__DOTDIR/__USER.$USER/.dotfile" 241 | rmdir "dotsrepo/__DOTDIR/__USER.$USER/.dotdir/" 242 | dotploy.sh deploy "dotsrepo" "dotsdest" 243 | _test_expect_symlink "dotsdest/.dotdir" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotdir" 244 | _test_expect_symlink "dotsdest/.dotfile" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotfile" 245 | ' 246 | 247 | _test_run "Fallback host and user based to shared" ' 248 | repo_layer=( 249 | "dotsrepo/__DOTDIR/.dotdir/" 250 | "dotsrepo/__DOTDIR/.dotfile" 251 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir/" 252 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotfile" 253 | ) 254 | _make_layer "${repo_layer[@]}" 255 | dotploy.sh deploy "dotsrepo" "dotsdest" 256 | rm "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotfile" 257 | rmdir "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir" 258 | dotploy.sh deploy "dotsrepo" "dotsdest" 259 | _test_expect_symlink "dotsdest/.dotdir" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotdir" 260 | _test_expect_symlink "dotsdest/.dotfile" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotfile" 261 | ' 262 | 263 | _test_run "Fallback host and user based deployment to user based" ' 264 | repo_layer=( 265 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir/" 266 | "dotsrepo/__DOTDIR/__USER.$USER/.dotfile" 267 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir/" 268 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotfile" 269 | ) 270 | _make_layer "${repo_layer[@]}" 271 | dotploy.sh deploy "dotsrepo" "dotsdest" 272 | rm "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotfile" 273 | rmdir "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir/" 274 | dotploy.sh deploy "dotsrepo" "dotsdest" 275 | _test_expect_symlink "dotsdest/.dotdir" "$TEST_FIELD/dotsrepo/__DOTDIR/__USER.$USER/.dotdir" 276 | _test_expect_symlink "dotsdest/.dotfile" "$TEST_FIELD/dotsrepo/__DOTDIR/__USER.$USER/.dotfile" 277 | ' 278 | 279 | _test_run "Fallback host and user based deployment to host based" ' 280 | repo_layer=( 281 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir/" 282 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotfile" 283 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir/" 284 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotfile" 285 | ) 286 | _make_layer "${repo_layer[@]}" 287 | dotploy.sh deploy "dotsrepo" "dotsdest" 288 | rm "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotfile" 289 | rmdir "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir" 290 | dotploy.sh deploy "dotsrepo" "dotsdest" 291 | _test_expect_symlink "dotsdest/.dotdir" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir" 292 | _test_expect_symlink "dotsdest/.dotfile" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotfile" 293 | ' 294 | 295 | _test_run "Fallback host and user based deployment to host based when __USER and __HOST both there" ' 296 | repo_layer=( 297 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir/" 298 | "dotsrepo/__DOTDIR/__USER.$USER/.dotfile" 299 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir/" 300 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotfile" 301 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir/" 302 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotfile" 303 | ) 304 | _make_layer "${repo_layer[@]}" 305 | dotploy.sh deploy "dotsrepo" dotsdest 306 | rm "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotfile" 307 | rmdir "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir" 308 | dotploy.sh deploy "dotsrepo" "dotsdest" 309 | _test_expect_symlink "dotsdest/.dotdir" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir" 310 | _test_expect_symlink "dotsdest/.dotfile" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotfile" 311 | ' 312 | 313 | _test_run "Backup if destination already exists" ' 314 | repo_layer=( 315 | "dotsdest/.dotdir1/" 316 | "dotsdest/.dotfile1" 317 | "dotsrepo/__DOTDIR/.dotdir1/" 318 | "dotsrepo/__DOTDIR/.dotfile1" 319 | "dotsdest/.dotdir2/" 320 | "dotsdest/.dotfile2" 321 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/" 322 | "dotsrepo/__DOTDIR/__USER.$USER/.dotfile2" 323 | "dotsdest/.dotdir3/" 324 | "dotsdest/.dotfile3" 325 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/" 326 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotfile3" 327 | "dotsdest/.dotdir4/" 328 | "dotsdest/.dotfile4" 329 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/" 330 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotfile4" 331 | ) 332 | _make_layer "${repo_layer[@]}" 333 | dotploy.sh deploy "dotsrepo" "dotsdest" 334 | _test_expect_expr_true "test -d dotsdest/.dotdir1" 335 | _test_expect_expr_true "test -f dotsdest/.dotfile1" 336 | _test_expect_expr_true "test -d dotsdest/.dotdir2" 337 | _test_expect_expr_true "test -f dotsdest/.dotfile2" 338 | _test_expect_expr_true "test -d dotsdest/.dotdir3" 339 | _test_expect_expr_true "test -f dotsdest/.dotfile3" 340 | _test_expect_expr_true "test -d dotsdest/.dotdir4" 341 | _test_expect_expr_true "test -f dotsdest/.dotfile4" 342 | ' 343 | _test_run "Backup if destination already exists with --force option" ' 344 | repo_layer=( 345 | "dotsdest/.dotdir1/" 346 | "dotsdest/.dotfile1" 347 | "dotsrepo/__DOTDIR/.dotdir1/" 348 | "dotsrepo/__DOTDIR/.dotfile1" 349 | "dotsdest/.dotdir2/" 350 | "dotsdest/.dotfile2" 351 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/" 352 | "dotsrepo/__DOTDIR/__USER.$USER/.dotfile2" 353 | "dotsdest/.dotdir3/" 354 | "dotsdest/.dotfile3" 355 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/" 356 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotfile3" 357 | "dotsdest/.dotdir4/" 358 | "dotsdest/.dotfile4" 359 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/" 360 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotfile4" 361 | ) 362 | _make_layer "${repo_layer[@]}" 363 | _test_expect_missing "dotsdest/.dotploy/backup" 364 | dotploy.sh deploy --force "dotsrepo" "dotsdest" 365 | _test_expect_directory "dotsdest/.dotploy/backup" 366 | _test_expect_expr_true "ls -RA dotsdest/.dotploy/backup | grep -q .dotdir1" 367 | _test_expect_expr_true "ls -RA dotsdest/.dotploy/backup | grep -q .dotfile1" 368 | _test_expect_expr_true "ls -RA dotsdest/.dotploy/backup | grep -q .dotdir2" 369 | _test_expect_expr_true "ls -RA dotsdest/.dotploy/backup | grep -q .dotfile2" 370 | _test_expect_expr_true "ls -RA dotsdest/.dotploy/backup | grep -q .dotdir3" 371 | _test_expect_expr_true "ls -RA dotsdest/.dotploy/backup | grep -q .dotfile3" 372 | _test_expect_expr_true "ls -RA dotsdest/.dotploy/backup | grep -q .dotdir4" 373 | _test_expect_expr_true "ls -RA dotsdest/.dotploy/backup | grep -q .dotfile4" 374 | ' 375 | 376 | _test_run "Whether __IGNORE works as expected" ' 377 | repo_layer=( 378 | "dotsrepo/__DOTDIR/__IGNORE" 379 | "dotsrepo/__DOTDIR/dir1/" 380 | "dotsrepo/__DOTDIR/file1" 381 | "dotsrepo/__DOTDIR/.dotdir1/" 382 | "dotsrepo/__DOTDIR/.dotfile1" 383 | "dotsrepo/__DOTDIR/__USER.$USER/__IGNORE" 384 | "dotsrepo/__DOTDIR/__USER.$USER/dir2/" 385 | "dotsrepo/__DOTDIR/__USER.$USER/file2" 386 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/" 387 | "dotsrepo/__DOTDIR/__USER.$USER/.dotfile2" 388 | "dotsrepo/__DOTDIR/__HOST.$HOST/__IGNORE" 389 | "dotsrepo/__DOTDIR/__HOST.$HOST/dir3/" 390 | "dotsrepo/__DOTDIR/__HOST.$HOST/file3" 391 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/" 392 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotfile3" 393 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/__IGNORE" 394 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/dir4/" 395 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/file4" 396 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/" 397 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotfile4" 398 | ) 399 | _make_layer "${repo_layer[@]}" 400 | echo "^dir1$" >> "dotsrepo/__DOTDIR/__IGNORE" 401 | echo "^file1$" >> "dotsrepo/__DOTDIR/__IGNORE" 402 | echo "^dir2$" >> "dotsrepo/__DOTDIR/__USER.$USER/__IGNORE" 403 | echo "^file2$" >> "dotsrepo/__DOTDIR/__USER.$USER/__IGNORE" 404 | echo "^dir3$" >> "dotsrepo/__DOTDIR/__HOST.$HOST/__IGNORE" 405 | echo "^file3$" >> "dotsrepo/__DOTDIR/__HOST.$HOST/__IGNORE" 406 | echo "^dir4$" >> "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/__IGNORE" 407 | echo "^file4$" >> "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/__IGNORE" 408 | dotploy.sh deploy "dotsrepo" "dotsdest" 409 | _test_expect_missing "dotsdest/dir1" 410 | _test_expect_missing "dotsdest/file1" 411 | _test_expect_missing "dotsdest/dir2" 412 | _test_expect_missing "dotsdest/file2" 413 | _test_expect_missing "dotsdest/dir3" 414 | _test_expect_missing "dotsdest/file3" 415 | _test_expect_missing "dotsdest/dir4" 416 | _test_expect_missing "dotsdest/file4" 417 | _test_expect_symlink "dotsdest/.dotdir1" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotdir1" 418 | _test_expect_symlink "dotsdest/.dotfile1" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotfile1" 419 | _test_expect_symlink "dotsdest/.dotdir2" "$TEST_FIELD/dotsrepo/__DOTDIR/__USER.$USER/.dotdir2" 420 | _test_expect_symlink "dotsdest/.dotfile2" "$TEST_FIELD/dotsrepo/__DOTDIR/__USER.$USER/.dotfile2" 421 | _test_expect_symlink "dotsdest/.dotdir3" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3" 422 | _test_expect_symlink "dotsdest/.dotfile3" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotfile3" 423 | _test_expect_symlink "dotsdest/.dotdir4" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4" 424 | _test_expect_symlink "dotsdest/.dotfile4" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotfile4" 425 | ' 426 | 427 | _test_run "Directory contains __KEEPED deployment" ' 428 | repo_layer=( 429 | "dotsrepo/__DOTDIR/.dotdir1/__KEEPED" 430 | "dotsrepo/__DOTDIR/.dotdir1/subdir/" 431 | "dotsrepo/__DOTDIR/.dotdir1/subfile" 432 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/__KEEPED" 433 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/subdir/" 434 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/subfile" 435 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/__KEEPED" 436 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/subdir/" 437 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/subfile" 438 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/__KEEPED" 439 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/subdir/" 440 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/subfile" 441 | ) 442 | _make_layer "${repo_layer[@]}" 443 | dotploy.sh deploy "dotsrepo" "dotsdest" 444 | _test_expect_directory "dotsdest/.dotdir1" 445 | _test_expect_directory "dotsdest/.dotdir2" 446 | _test_expect_directory "dotsdest/.dotdir3" 447 | _test_expect_directory "dotsdest/.dotdir4" 448 | _test_expect_symlink "dotsdest/.dotdir1/subdir" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotdir1/subdir" 449 | _test_expect_symlink "dotsdest/.dotdir1/subfile" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotdir1/subfile" 450 | _test_expect_symlink "dotsdest/.dotdir2/subdir" "$TEST_FIELD/dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/subdir" 451 | _test_expect_symlink "dotsdest/.dotdir2/subfile" "$TEST_FIELD/dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/subfile" 452 | _test_expect_symlink "dotsdest/.dotdir3/subdir" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/subdir" 453 | _test_expect_symlink "dotsdest/.dotdir3/subfile" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/subfile" 454 | _test_expect_symlink "dotsdest/.dotdir4/subdir" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/subdir" 455 | _test_expect_symlink "dotsdest/.dotdir4/subfile" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/subfile" 456 | ' 457 | 458 | _test_run "Destination of the directory conatains __KEEPED exists as a file" ' 459 | repo_layer=( 460 | "dotsdest/.dotdir1" 461 | "dotsdest/.dotdir2" 462 | "dotsdest/.dotdir3" 463 | "dotsdest/.dotdir4" 464 | "dotsrepo/__DOTDIR/.dotdir1/__KEEPED" 465 | "dotsrepo/__DOTDIR/.dotdir1/subdir/" 466 | "dotsrepo/__DOTDIR/.dotdir1/subfile" 467 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/__KEEPED" 468 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/subdir/" 469 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/subfile" 470 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/__KEEPED" 471 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/subdir/" 472 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/subfile" 473 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/__KEEPED" 474 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/subdir/" 475 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/subfile" 476 | ) 477 | _make_layer "${repo_layer[@]}" 478 | dotploy.sh deploy "dotsrepo" "dotsdest" 479 | _test_expect_directory "dotsdest/.dotdir1" 480 | _test_expect_directory "dotsdest/.dotdir2" 481 | _test_expect_directory "dotsdest/.dotdir3" 482 | _test_expect_directory "dotsdest/.dotdir4" 483 | _test_expect_symlink "dotsdest/.dotdir1/subdir" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotdir1/subdir" 484 | _test_expect_symlink "dotsdest/.dotdir1/subfile" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotdir1/subfile" 485 | _test_expect_symlink "dotsdest/.dotdir2/subdir" "$TEST_FIELD/dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/subdir" 486 | _test_expect_symlink "dotsdest/.dotdir2/subfile" "$TEST_FIELD/dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/subfile" 487 | _test_expect_symlink "dotsdest/.dotdir3/subdir" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/subdir" 488 | _test_expect_symlink "dotsdest/.dotdir3/subfile" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/subfile" 489 | _test_expect_symlink "dotsdest/.dotdir4/subdir" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/subdir" 490 | _test_expect_symlink "dotsdest/.dotdir4/subfile" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/subfile" 491 | ' 492 | 493 | _test_run "Destination of the directory conatains __KEEPED exists as a directory" ' 494 | repo_layer=( 495 | "dotsdest/.dotdir1/" 496 | "dotsdest/.dotdir2/" 497 | "dotsdest/.dotdir3/" 498 | "dotsdest/.dotdir4/" 499 | "dotsrepo/__DOTDIR/.dotdir1/__KEEPED" 500 | "dotsrepo/__DOTDIR/.dotdir1/subdir/" 501 | "dotsrepo/__DOTDIR/.dotdir1/subfile" 502 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/__KEEPED" 503 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/subdir/" 504 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/subfile" 505 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/__KEEPED" 506 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/subdir/" 507 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/subfile" 508 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/__KEEPED" 509 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/subdir/" 510 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/subfile" 511 | ) 512 | _make_layer "${repo_layer[@]}" 513 | dotploy.sh deploy "dotsrepo" "dotsdest" 514 | _test_expect_directory "dotsdest/.dotdir1" 515 | _test_expect_directory "dotsdest/.dotdir2" 516 | _test_expect_directory "dotsdest/.dotdir3" 517 | _test_expect_directory "dotsdest/.dotdir4" 518 | _test_expect_symlink "dotsdest/.dotdir1/subdir" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotdir1/subdir" 519 | _test_expect_symlink "dotsdest/.dotdir1/subfile" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotdir1/subfile" 520 | _test_expect_symlink "dotsdest/.dotdir2/subdir" "$TEST_FIELD/dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/subdir" 521 | _test_expect_symlink "dotsdest/.dotdir2/subfile" "$TEST_FIELD/dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/subfile" 522 | _test_expect_symlink "dotsdest/.dotdir3/subdir" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/subdir" 523 | _test_expect_symlink "dotsdest/.dotdir3/subfile" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/subfile" 524 | _test_expect_symlink "dotsdest/.dotdir4/subdir" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/subdir" 525 | _test_expect_symlink "dotsdest/.dotdir4/subfile" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/subfile" 526 | ' 527 | 528 | _test_run "Whether __IGNORE and __KEEPED works together" ' 529 | repo_layer=( 530 | "dotsrepo/__DOTDIR/.dotdir1/__IGNORE" 531 | "dotsrepo/__DOTDIR/.dotdir1/__KEEPED" 532 | "dotsrepo/__DOTDIR/.dotdir1/dir/" 533 | "dotsrepo/__DOTDIR/.dotdir1/file" 534 | "dotsrepo/__DOTDIR/.dotdir1/subdir/" 535 | "dotsrepo/__DOTDIR/.dotdir1/subfile" 536 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/__IGNORE" 537 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/__KEEPED" 538 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/dir/" 539 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/file" 540 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/subdir/" 541 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/subfile" 542 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/__IGNORE" 543 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/__KEEPED" 544 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/dir/" 545 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/file" 546 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/subdir/" 547 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/subfile" 548 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/__IGNORE" 549 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/__KEEPED" 550 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/dir/" 551 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/file" 552 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/subdir/" 553 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/subfile" 554 | ) 555 | _make_layer "${repo_layer[@]}" 556 | echo "^dir$" >> "dotsrepo/__DOTDIR/.dotdir1/__IGNORE" 557 | echo "^file$" >> "dotsrepo/__DOTDIR/.dotdir1/__IGNORE" 558 | echo "^dir$" >> "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/__IGNORE" 559 | echo "^file$" >> "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/__IGNORE" 560 | echo "^dir$" >> "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/__IGNORE" 561 | echo "^file$" >> "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/__IGNORE" 562 | echo "^dir$" >> "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/__IGNORE" 563 | echo "^file$" >> "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/__IGNORE" 564 | dotploy.sh deploy "dotsrepo" "dotsdest" 565 | _test_expect_missing "dotsdest/.dotdir1/dir" 566 | _test_expect_missing "dotsdest/.dotdir1/file" 567 | _test_expect_missing "dotsdest/.dotdir2/dir" 568 | _test_expect_missing "dotsdest/.dotdir2/file" 569 | _test_expect_missing "dotsdest/.dotdir3/dir" 570 | _test_expect_missing "dotsdest/.dotdir3/file" 571 | _test_expect_missing "dotsdest/.dotdir4/dir" 572 | _test_expect_missing "dotsdest/.dotdir4/file" 573 | _test_expect_symlink "dotsdest/.dotdir1/subdir" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotdir1/subdir" 574 | _test_expect_symlink "dotsdest/.dotdir1/subfile" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotdir1/subfile" 575 | _test_expect_symlink "dotsdest/.dotdir2/subdir" "$TEST_FIELD/dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/subdir" 576 | _test_expect_symlink "dotsdest/.dotdir2/subfile" "$TEST_FIELD/dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/subfile" 577 | _test_expect_symlink "dotsdest/.dotdir3/subdir" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/subdir" 578 | _test_expect_symlink "dotsdest/.dotdir3/subfile" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/subfile" 579 | _test_expect_symlink "dotsdest/.dotdir4/subdir" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/subdir" 580 | _test_expect_symlink "dotsdest/.dotdir4/subfile" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/subfile" 581 | ' 582 | 583 | _test_run "Use __IGNORE ignore directory contains __KEEPED" ' 584 | repo_layer=( 585 | "dotsrepo/__DOTDIR/__IGNORE" 586 | "dotsrepo/__DOTDIR/.dotdir1/__KEEPED" 587 | "dotsrepo/__DOTDIR/.dotdir1/subdir/" 588 | "dotsrepo/__DOTDIR/.dotdir1/subfile" 589 | "dotsrepo/__DOTDIR/__USER.$USER/__IGNORE" 590 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/__KEEPED" 591 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/subdir/" 592 | "dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/subfile" 593 | "dotsrepo/__DOTDIR/__HOST.$HOST/__IGNORE" 594 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/__KEEPED" 595 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/subdir/" 596 | "dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir3/subfile" 597 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/__IGNORE" 598 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/__KEEPED" 599 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/subdir/" 600 | "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir4/subfile" 601 | ) 602 | _make_layer "${repo_layer[@]}" 603 | echo "^.dotdir1$" >> "dotsrepo/__DOTDIR/__IGNORE" 604 | echo "^.dotdir2$" >> "dotsrepo/__DOTDIR/__USER.$USER/__IGNORE" 605 | echo "^.dotdir3$" >> "dotsrepo/__DOTDIR/__HOST.$HOST/__IGNORE" 606 | echo "^.dotdir4$" >> "dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/__IGNORE" 607 | dotploy.sh deploy "dotsrepo" "dotsdest" 608 | _test_expect_missing "dotsdest/.dotdir1" 609 | _test_expect_missing "dotsdest/.dotdir2" 610 | _test_expect_missing "dotsdest/.dotdir3" 611 | _test_expect_missing "dotsdest/.dotdir4" 612 | ' 613 | 614 | _test_run "Local file/directory deploy" ' 615 | repo_layer=( 616 | "normaldir/" 617 | "normalfile" 618 | "normaldir/normalfile" 619 | "dotsdest/normaldir1/" 620 | "dotsdest/normalfile1" 621 | "dotsrepo/__DOTDIR/.dotfile1.__SRC" 622 | "dotsrepo/__DOTDIR/.dotfile2.__SRC" 623 | "dotsrepo/__DOTDIR/.dotfile3.__SRC" 624 | "dotsrepo/__DOTDIR/.dotfile4.__SRC" 625 | "dotsrepo/__DOTDIR/.dotfile5.__SRC" 626 | "dotsrepo/__DOTDIR/.dotfile6.__SRC" 627 | ) 628 | _make_layer "${repo_layer[@]}" 629 | ( cd dotsdest/normaldir1; ln -s ../normalfile1 normalfile1 ) 630 | echo "$TEST_FIELD/normaldir" >> "dotsrepo/__DOTDIR/.dotfile1.__SRC" 631 | echo "$TEST_FIELD/normalfile" >> "dotsrepo/__DOTDIR/.dotfile2.__SRC" 632 | echo "$TEST_FIELD/normaldir/normalfile" >> "dotsrepo/__DOTDIR/.dotfile3.__SRC" 633 | echo "normaldir1" > "dotsrepo/__DOTDIR/.dotfile4.__SRC" 634 | echo "normalfile1" > "dotsrepo/__DOTDIR/.dotfile5.__SRC" 635 | echo "normaldir1/normalfile1" > "dotsrepo/__DOTDIR/.dotfile6.__SRC" 636 | dotploy.sh deploy "dotsrepo" "dotsdest" 637 | _test_expect_symlink "dotsdest/.dotfile1" "$TEST_FIELD/normaldir" 638 | _test_expect_symlink "dotsdest/.dotfile2" "$TEST_FIELD/normalfile" 639 | _test_expect_symlink "dotsdest/.dotfile3" "$TEST_FIELD/normaldir/normalfile" 640 | _test_expect_symlink "dotsdest/.dotfile4" "normaldir1" 641 | _test_expect_symlink "dotsdest/.dotfile5" "normalfile1" 642 | _test_expect_symlink "dotsdest/.dotfile6" "normaldir1/normalfile1" 643 | output=$(dotploy.sh deploy "dotsrepo" "dotsdest" 2>&1) && echo "$output" 644 | _test_expect_unmatch "$output" "Warning: $TEST_FIELD/dotsdest/.dotfile3 already exists, use --force option to force deploying" 645 | _test_expect_unmatch "$output" "Warning: $TEST_FIELD/dotsdest/.dotfile4 already exists, use --force option to force deploying" 646 | _test_expect_unmatch "$output" "Warning: $TEST_FIELD/dotsdest/.dotfile5 already exists, use --force option to force deploying" 647 | ' 648 | 649 | _test_run "Local file/directory deploy with target missing" ' 650 | repo_layer=( 651 | "dotsrepo/__DOTDIR/.dotfile1.__SRC" 652 | "dotsrepo/__DOTDIR/.dotfile2.__SRC" 653 | "dotsrepo/__DOTDIR/.dotfile3.__SRC" 654 | "dotsrepo/__DOTDIR/.dotfile4.__SRC" 655 | "dotsrepo/__DOTDIR/.dotfile5.__SRC" 656 | "dotsrepo/__DOTDIR/.dotfile6.__SRC" 657 | ) 658 | _make_layer "${repo_layer[@]}" 659 | echo "$TEST_FIELD/normaldir" > "dotsrepo/__DOTDIR/.dotfile1.__SRC" 660 | echo "$TEST_FIELD/normalfile" > "dotsrepo/__DOTDIR/.dotfile2.__SRC" 661 | echo "$TEST_FIELD/normaldir/normalfile" >> "dotsrepo/__DOTDIR/.dotfile3.__SRC" 662 | echo "normaldir1" > "dotsrepo/__DOTDIR/.dotfile4.__SRC" 663 | echo "normalfile1" > "dotsrepo/__DOTDIR/.dotfile5.__SRC" 664 | echo "normaldir1/normalfile1" > "dotsrepo/__DOTDIR/.dotfile6.__SRC" 665 | dotploy.sh deploy "dotsrepo" "dotsdest" 666 | _test_expect_symlink "dotsdest/.dotfile1" "$TEST_FIELD/normaldir" 667 | _test_expect_symlink "dotsdest/.dotfile2" "$TEST_FIELD/normalfile" 668 | _test_expect_symlink "dotsdest/.dotfile3" "$TEST_FIELD/normaldir/normalfile" 669 | _test_expect_symlink "dotsdest/.dotfile4" "normaldir1" 670 | _test_expect_symlink "dotsdest/.dotfile5" "normalfile1" 671 | _test_expect_symlink "dotsdest/.dotfile6" "normaldir1/normalfile1" 672 | ' 673 | 674 | _test_run "Remote git repository deploy" ' 675 | _git_set_up 676 | repo_layer=( 677 | "dotsrepo/__DOTDIR/.dotfile.__SRC" 678 | ) 679 | _make_layer "${repo_layer[@]}" 680 | echo "git+file://$TEST_FIELD/test.git" > "dotsrepo/__DOTDIR/.dotfile.__SRC" 681 | dotploy.sh deploy "dotsrepo" "dotsdest" 682 | _test_expect_symlink "dotsdest/.dotfile" "$TEST_FIELD/dotsdest/.dotploy/vcs/test.dotfile" 683 | output=$(dotploy.sh deploy "dotsrepo" "dotsdest" 2>&1) && echo "$output" 684 | _test_expect_unmatch "$output" "Warning: $TEST_FIELD/dotsdest/.dotfile already exists, use --force option to force deploying" 685 | ' 686 | 687 | _test_run "Remote git repository deploy with differnt HEAD" ' 688 | _git_set_up 689 | repo_layer=( 690 | "dotsrepo/__DOTDIR/.dotfile.__SRC" 691 | ) 692 | _make_layer "${repo_layer[@]}" 693 | echo "git+file://$TEST_FIELD/test.git" > "dotsrepo/__DOTDIR/.dotfile.__SRC" 694 | dotploy.sh deploy "dotsrepo" "dotsdest" 695 | _git_checkout develop 696 | dotploy.sh deploy "dotsrepo" "dotsdest" 697 | _test_expect_expr_true "test $(cd dotsdest/.dotploy/vcs/test.dotfile;git rev-parse --short HEAD) = $(cd test.git;git rev-parse --short develop)" 698 | ' 699 | 700 | _test_run "Remote git repository deploy with different HEAD and local changes" ' 701 | _git_set_up 702 | repo_layer=( 703 | "dotsrepo/__DOTDIR/.dotfile1.__SRC" 704 | "dotsrepo/__DOTDIR/.dotfile2.__SRC" 705 | "dotsrepo/__DOTDIR/.dotfile3.__SRC" 706 | "dotsrepo/__DOTDIR/.dotfile4.__SRC" 707 | "dotsrepo/__DOTDIR/.dotfile5.__SRC" 708 | ) 709 | _make_layer "${repo_layer[@]}" 710 | echo "git+file://$TEST_FIELD/test.git" > "dotsrepo/__DOTDIR/.dotfile1.__SRC" 711 | echo "git+file://$TEST_FIELD/test.git" > "dotsrepo/__DOTDIR/.dotfile2.__SRC" 712 | echo "git+file://$TEST_FIELD/test.git" > "dotsrepo/__DOTDIR/.dotfile3.__SRC" 713 | echo "git+file://$TEST_FIELD/test.git" > "dotsrepo/__DOTDIR/.dotfile4.__SRC" 714 | echo "git+file://$TEST_FIELD/test.git" > "dotsrepo/__DOTDIR/.dotfile5.__SRC" 715 | dotploy.sh deploy "dotsrepo" "dotsdest" 716 | _git_checkout develop 717 | # local has unstaged chagnes 718 | ( 719 | exec &>/dev/null 720 | cd dotsdest/.dotploy/vcs/test.dotfile1 721 | rm 1 722 | ) 723 | # local has staged chagnes 724 | ( 725 | exec &>/dev/null 726 | cd dotsdest/.dotploy/vcs/test.dotfile2 727 | git rm 1 728 | ) 729 | # local tracking branch has commit not in remote 730 | ( 731 | exec &>/dev/null 732 | cd dotsdest/.dotploy/vcs/test.dotfile3 733 | touch test 734 | git add test 735 | git commit -m "test" 736 | ) 737 | # local untracking branch has commit not in remote 738 | ( 739 | exec &>/dev/null 740 | cd dotsdest/.dotploy/vcs/test.dotfile4 741 | git co -b test 742 | touch test 743 | git add test 744 | git commit -m "test" 745 | ) 746 | # local is in detached head state and has commit not in remote 747 | ( 748 | exec &>/dev/null 749 | cd dotsdest/.dotploy/vcs/test.dotfile5 750 | git co HEAD~ 751 | touch test 752 | git add test 753 | git commit -m "test" 754 | ) 755 | output=$(dotploy.sh deploy "dotsrepo" "dotsdest" 2>&1) && echo "$output" 756 | _test_expect_match "$output" "Warning: Our clone of the repository $TEST_FIELD/dotsdest/.dotploy/vcs/test.dotfile1 has local changes, abort further operation, please resolve first." 757 | _test_expect_expr_false "test $(cd dotsdest/.dotploy/vcs/test.dotfile1;git rev-parse --short HEAD) = $(cd test.git;git rev-parse --short develop)" 758 | _test_expect_match "$output" "Warning: Our clone of the repository $TEST_FIELD/dotsdest/.dotploy/vcs/test.dotfile2 has local changes, abort further operation, please resolve first." 759 | _test_expect_expr_false "test $(cd dotsdest/.dotploy/vcs/test.dotfile2;git rev-parse --short HEAD) = $(cd test.git;git rev-parse --short develop)" 760 | _test_expect_match "$output" "Warning: Our clone of the repository $TEST_FIELD/dotsdest/.dotploy/vcs/test.dotfile3 has local changes, abort further operation, please resolve first." 761 | _test_expect_expr_false "test $(cd dotsdest/.dotploy/vcs/test.dotfile3;git rev-parse --short HEAD) = $(cd test.git;git rev-parse --short develop)" 762 | _test_expect_unmatch "$output" "Warning: Our clone of the repository $TEST_FIELD/dotsdest/.dotploy/vcs/test.dotfile4 has local changes, abort further operation, please resolve first." 763 | _test_expect_expr_true "test $(cd dotsdest/.dotploy/vcs/test.dotfile4;git rev-parse --short HEAD) = $(cd test.git;git rev-parse --short develop)" 764 | _test_expect_match "$output" "Warning: Our clone of the repository $TEST_FIELD/dotsdest/.dotploy/vcs/test.dotfile5 has local changes, abort further operation, please resolve first." 765 | _test_expect_expr_false "test $(cd dotsdest/.dotploy/vcs/test.dotfile5;git rev-parse --short HEAD) = $(cd test.git;git rev-parse --short develop)" 766 | ' 767 | 768 | _test_run "Remote git repository deploy with wrong repo url" ' 769 | _git_set_up 770 | repo_layer=( 771 | "dotsrepo/__DOTDIR/.dotfile.__SRC" 772 | ) 773 | _make_layer "${repo_layer[@]}" 774 | echo "git+file://$TEST_FIELD/test1.git" > "dotsrepo/__DOTDIR/.dotfile.__SRC" 775 | output=$(dotploy.sh deploy "dotsrepo" "dotsdest" 2>&1) && echo "$output" 776 | _test_expect_match "$output" "ERROR: Failed to clone repository '\''$TEST_FIELD/test1.git'\'' to '\''$TEST_FIELD/dotsdest/.dotploy/vcs/test1.dotfile'\''." 777 | _test_expect_missing "dotsdest/.dotfile" 778 | ' 779 | 780 | _test_run "Remote git repository deploy with the location to be cloned to exists" ' 781 | _git_set_up 782 | repo_layer=( 783 | "dotsrepo/__DOTDIR/.dotfile.__SRC" 784 | ) 785 | _make_layer "${repo_layer[@]}" 786 | echo "git+file://$TEST_FIELD/test.git" > "dotsrepo/__DOTDIR/.dotfile.__SRC" 787 | ( 788 | mkdir -p dotsdest/.dotploy/vcs/ 789 | cd dotsdest/.dotploy/vcs/ 790 | touch test.dotfile 791 | ) 792 | output=$(dotploy.sh deploy "dotsrepo" "dotsdest" 2>&1) && echo "$output" 793 | bakdir=dotsdest/.dotploy/backup/$(ls -1 --color=none dotsdest/.dotploy/backup) 794 | _test_expect_match "$output" "Warning: '\''$TEST_FIELD/dotsdest/.dotploy/vcs/test.dotfile'\'' is already there, backup to '\''$TEST_FIELD/$bakdir'\''." 795 | _test_expect_exists $bakdir/test.dotfile 796 | ' 797 | 798 | _test_run "Remote git repository deploy with the existing repo upstream incorrect" ' 799 | _git_set_up 800 | repo_layer=( 801 | "dotsrepo/__DOTDIR/.dotfile.__SRC" 802 | ) 803 | _make_layer "${repo_layer[@]}" 804 | echo "git+file://$TEST_FIELD/test.git" > "dotsrepo/__DOTDIR/.dotfile.__SRC" 805 | ( 806 | mkdir -p dotsdest/.dotploy/vcs/ 807 | cd dotsdest/.dotploy/vcs/ 808 | git clone $TEST_FIELD/test.git test.dotfile &>/dev/null 809 | cd test.dotfile 810 | git remote set-url --add origin $TEST_FIELD/test1.git 811 | ) 812 | output=$(dotploy.sh deploy "dotsrepo" "dotsdest" 2>&1) && echo "$output" 813 | bakdir=dotsdest/.dotploy/backup/$(ls -1 --color=none dotsdest/.dotploy/backup) 814 | _test_expect_match "$output" "Warning: '\''$TEST_FIELD/dotsdest/.dotploy/vcs/test.dotfile'\'' is already there, backup to '\''$TEST_FIELD/$bakdir'\''." 815 | _test_expect_directory $bakdir/test.dotfile 816 | ' 817 | 818 | _test_run "Remote git repository deploy with the existing repo upstream being dead" ' 819 | _git_set_up 820 | repo_layer=( 821 | "dotsrepo/__DOTDIR/.dotfile.__SRC" 822 | ) 823 | _make_layer "${repo_layer[@]}" 824 | echo "git+file://$TEST_FIELD/test.git" > "dotsrepo/__DOTDIR/.dotfile.__SRC" 825 | ( 826 | mkdir -p dotsdest/.dotploy/vcs/ 827 | cd dotsdest/.dotploy/vcs/ 828 | git clone $TEST_FIELD/test.git test.dotfile &>/dev/null 829 | ) 830 | rm -rf $TEST_FIELD/test.git 831 | output=$(dotploy.sh deploy "dotsrepo" "dotsdest" 2>&1) && echo "$output" 832 | _test_expect_match "$output" "Warning: Failed to fetch upstream '\''$TEST_FIELD/test.git'\'' in '\''$TEST_FIELD/dotsdest/.dotploy/vcs/test.dotfile'\''." 833 | ' 834 | 835 | _test_run "Remote git repository deploy with reference specified" ' 836 | _git_set_up 837 | _git_commit 5/6 6 6 838 | _git_checkout develop 839 | _git_commit 7/8 8 8 840 | _git_checkout master 841 | repo_layer=( 842 | "dotsrepo/__DOTDIR/.dotfile1.__SRC" 843 | "dotsrepo/__DOTDIR/.dotfile2.__SRC" 844 | "dotsrepo/__DOTDIR/.dotfile3.__SRC" 845 | "dotsrepo/__DOTDIR/.dotfile4.__SRC" 846 | "dotsrepo/__DOTDIR/.dotfile5.__SRC" 847 | ) 848 | _make_layer "${repo_layer[@]}" 849 | echo "test1::git+file://$TEST_FIELD/test.git#tag=v0.1" > "dotsrepo/__DOTDIR/.dotfile1.__SRC" 850 | echo "test2::git+file://$TEST_FIELD/test.git#branch=develop" > "dotsrepo/__DOTDIR/.dotfile2.__SRC" 851 | echo "test3::git+file://$TEST_FIELD/test.git#commit=$(cd test.git;git rev-parse --short v0.1~)" > "dotsrepo/__DOTDIR/.dotfile3.__SRC" 852 | echo "test4::git+file://$TEST_FIELD/test.git#file=5/6" > "dotsrepo/__DOTDIR/.dotfile4.__SRC" 853 | echo "test5::git+file://$TEST_FIELD/test.git#branch=develop&file=7/8" > "dotsrepo/__DOTDIR/.dotfile5.__SRC" 854 | dotploy.sh deploy "dotsrepo" "dotsdest" 855 | _test_expect_symlink "dotsdest/.dotfile1" "$TEST_FIELD/dotsdest/.dotploy/vcs/test1.dotfile1" 856 | _test_expect_expr_true "test $(cd dotsdest/.dotploy/vcs/test1.dotfile1;git rev-parse --short HEAD) = $(cd test.git;git rev-parse --short v0.1)" 857 | _test_expect_symlink "dotsdest/.dotfile2" "$TEST_FIELD/dotsdest/.dotploy/vcs/test2.dotfile2" 858 | _test_expect_expr_true "test $(cd dotsdest/.dotploy/vcs/test2.dotfile2;git rev-parse --short HEAD) = $(cd test.git;git rev-parse --short develop)" 859 | _test_expect_symlink "dotsdest/.dotfile3" "$TEST_FIELD/dotsdest/.dotploy/vcs/test3.dotfile3" 860 | _test_expect_expr_true "test $(cd dotsdest/.dotploy/vcs/test3.dotfile3;git rev-parse --short HEAD) = $(cd test.git;git rev-parse --short v0.1~)" 861 | _test_expect_symlink "dotsdest/.dotfile4" "$TEST_FIELD/dotsdest/.dotploy/vcs/test4.dotfile4/5/6" 862 | _test_expect_symlink "dotsdest/.dotfile5" "$TEST_FIELD/dotsdest/.dotploy/vcs/test5.dotfile5/7/8" 863 | _test_expect_expr_true "test $(cd dotsdest/.dotploy/vcs/test5.dotfile5;git rev-parse --short HEAD) = $(cd test.git;git rev-parse --short develop)" 864 | ' 865 | 866 | _test_run "Remote git repository deploy with updated remote branch reference" ' 867 | _git_set_up 868 | repo_layer=( 869 | "dotsrepo/__DOTDIR/.dotfile.__SRC" 870 | ) 871 | _make_layer "${repo_layer[@]}" 872 | echo "git+file://$TEST_FIELD/test.git#branch=develop" > "dotsrepo/__DOTDIR/.dotfile.__SRC" 873 | dotploy.sh deploy "dotsrepo" "dotsdest" 874 | _git_checkout develop 875 | _git_commit 5/6 6 6 876 | _git_checkout master 877 | dotploy.sh deploy "dotsrepo" "dotsdest" 878 | _test_expect_expr_true "test $(cd dotsdest/.dotploy/vcs/test.dotfile;git rev-parse --short HEAD) = $(cd test.git;git rev-parse --short develop)" 879 | ' 880 | 881 | _test_run "Remote git repository deploy with updated remote branch reference and local changes" ' 882 | _git_set_up 883 | repo_layer=( 884 | "dotsrepo/__DOTDIR/.dotfile1.__SRC" 885 | "dotsrepo/__DOTDIR/.dotfile2.__SRC" 886 | "dotsrepo/__DOTDIR/.dotfile3.__SRC" 887 | "dotsrepo/__DOTDIR/.dotfile4.__SRC" 888 | "dotsrepo/__DOTDIR/.dotfile5.__SRC" 889 | ) 890 | _make_layer "${repo_layer[@]}" 891 | echo "git+file://$TEST_FIELD/test.git#branch=develop" > "dotsrepo/__DOTDIR/.dotfile1.__SRC" 892 | echo "git+file://$TEST_FIELD/test.git#branch=develop" > "dotsrepo/__DOTDIR/.dotfile2.__SRC" 893 | echo "git+file://$TEST_FIELD/test.git#branch=develop" > "dotsrepo/__DOTDIR/.dotfile3.__SRC" 894 | echo "git+file://$TEST_FIELD/test.git#branch=develop" > "dotsrepo/__DOTDIR/.dotfile4.__SRC" 895 | echo "git+file://$TEST_FIELD/test.git#branch=develop" > "dotsrepo/__DOTDIR/.dotfile5.__SRC" 896 | dotploy.sh deploy "dotsrepo" "dotsdest" 897 | _git_checkout develop 898 | _git_commit 5/6 6 6 899 | _git_checkout master 900 | # local has unstaged chagnes 901 | ( 902 | exec &>/dev/null 903 | cd dotsdest/.dotploy/vcs/test.dotfile1 904 | rm 1 905 | ) 906 | # local has staged chagnes 907 | ( 908 | exec &>/dev/null 909 | cd dotsdest/.dotploy/vcs/test.dotfile2 910 | git rm 1 911 | ) 912 | # local tracking branch has commit not in remote 913 | ( 914 | exec &>/dev/null 915 | cd dotsdest/.dotploy/vcs/test.dotfile3 916 | touch test 917 | git add test 918 | git commit -m "test" 919 | ) 920 | # local untracking branch has commit not in remote 921 | ( 922 | exec &>/dev/null 923 | cd dotsdest/.dotploy/vcs/test.dotfile4 924 | git co -b test 925 | touch test 926 | git add test 927 | git commit -m "test" 928 | ) 929 | # local is in detached head state and has commit not in remote 930 | ( 931 | exec &>/dev/null 932 | cd dotsdest/.dotploy/vcs/test.dotfile5 933 | git co HEAD~ 934 | touch test 935 | git add test 936 | git commit -m "test" 937 | ) 938 | output=$(dotploy.sh deploy "dotsrepo" "dotsdest" 2>&1) && echo "$output" 939 | _test_expect_match "$output" "Warning: Our clone of the repository $TEST_FIELD/dotsdest/.dotploy/vcs/test.dotfile1 has local changes, abort further operation, please resolve first." 940 | _test_expect_expr_false "test $(cd dotsdest/.dotploy/vcs/test.dotfile1;git rev-parse --short HEAD) = $(cd test.git;git rev-parse --short develop)" 941 | _test_expect_match "$output" "Warning: Our clone of the repository $TEST_FIELD/dotsdest/.dotploy/vcs/test.dotfile2 has local changes, abort further operation, please resolve first." 942 | _test_expect_expr_false "test $(cd dotsdest/.dotploy/vcs/test.dotfile2;git rev-parse --short HEAD) = $(cd test.git;git rev-parse --short develop)" 943 | _test_expect_match "$output" "Warning: Our clone of the repository $TEST_FIELD/dotsdest/.dotploy/vcs/test.dotfile3 has local changes, abort further operation, please resolve first." 944 | _test_expect_expr_false "test $(cd dotsdest/.dotploy/vcs/test.dotfile3;git rev-parse --short HEAD) = $(cd test.git;git rev-parse --short develop)" 945 | _test_expect_unmatch "$output" "Warning: Our clone of the repository $TEST_FIELD/dotsdest/.dotploy/vcs/test.dotfile4 has local changes, abort further operation, please resolve first." 946 | _test_expect_expr_true "test $(cd dotsdest/.dotploy/vcs/test.dotfile4;git rev-parse --short HEAD) = $(cd test.git;git rev-parse --short develop)" 947 | _test_expect_match "$output" "Warning: Our clone of the repository $TEST_FIELD/dotsdest/.dotploy/vcs/test.dotfile5 has local changes, abort further operation, please resolve first." 948 | _test_expect_expr_false "test $(cd dotsdest/.dotploy/vcs/test.dotfile5;git rev-parse --short HEAD) = $(cd test.git;git rev-parse --short develop)" 949 | ' 950 | 951 | _test_run "Add given file to the dots repo" ' 952 | repo_layer=( 953 | "dotsdest/.dotdir1/" 954 | "dotsdest/.dotfile1" 955 | "dotsdest/.dotdir2/dotfile2" 956 | ) 957 | _make_layer "${repo_layer[@]}" 958 | for i in "${repo_layer[@]}" 959 | do 960 | dotploy.sh add $i "dotsrepo" "dotsdest" 961 | done 962 | _test_expect_expr_true "test -d dotsrepo/__DOTDIR/.dotdir1" 963 | _test_expect_symlink "dotsdest/.dotdir1" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotdir1" 964 | _test_expect_expr_true "test -f dotsrepo/__DOTDIR/.dotfile1" 965 | _test_expect_symlink "dotsdest/.dotfile1" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotfile1" 966 | _test_expect_expr_true "test -d dotsrepo/__DOTDIR/.dotdir2" 967 | _test_expect_expr_true "test -f dotsrepo/__DOTDIR/.dotdir2/dotfile2" 968 | _test_expect_symlink "dotsdest/.dotdir2/dotfile2" "$TEST_FIELD/dotsrepo/__DOTDIR/.dotdir2/dotfile2" 969 | ' 970 | 971 | _test_run "Add given file to the dots repo with --host" ' 972 | repo_layer=( 973 | "dotsdest/.dotdir1/" 974 | "dotsdest/.dotfile1" 975 | "dotsdest/.dotdir2/dotfile2" 976 | ) 977 | _make_layer "${repo_layer[@]}" 978 | for i in "${repo_layer[@]}" 979 | do 980 | dotploy.sh add --host $i "dotsrepo" "dotsdest" 981 | done 982 | _test_expect_expr_true "test -d dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir1" 983 | _test_expect_symlink "dotsdest/.dotdir1" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir1" 984 | _test_expect_expr_true "test -f dotsrepo/__DOTDIR/__HOST.$HOST/.dotfile1" 985 | _test_expect_symlink "dotsdest/.dotfile1" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotfile1" 986 | _test_expect_expr_true "test -f dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir2/dotfile2" 987 | _test_expect_symlink "dotsdest/.dotdir2/dotfile2" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/.dotdir2/dotfile2" 988 | ' 989 | 990 | _test_run "Add given file to the dots repo with --user" ' 991 | repo_layer=( 992 | "dotsdest/.dotdir1/" 993 | "dotsdest/.dotfile1" 994 | "dotsdest/.dotdir2/dotfile2" 995 | ) 996 | _make_layer "${repo_layer[@]}" 997 | for i in "${repo_layer[@]}" 998 | do 999 | dotploy.sh add --user $i "dotsrepo" "dotsdest" 1000 | done 1001 | _test_expect_expr_true "test -d dotsrepo/__DOTDIR/__USER.$USER/.dotdir1" 1002 | _test_expect_symlink "dotsdest/.dotdir1" "$TEST_FIELD/dotsrepo/__DOTDIR/__USER.$USER/.dotdir1" 1003 | _test_expect_expr_true "test -f dotsrepo/__DOTDIR/__USER.$USER/.dotfile1" 1004 | _test_expect_symlink "dotsdest/.dotfile1" "$TEST_FIELD/dotsrepo/__DOTDIR/__USER.$USER/.dotfile1" 1005 | _test_expect_expr_true "test -f dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/dotfile2" 1006 | _test_expect_symlink "dotsdest/.dotdir2/dotfile2" "$TEST_FIELD/dotsrepo/__DOTDIR/__USER.$USER/.dotdir2/dotfile2" 1007 | ' 1008 | 1009 | _test_run "Add given file to the dots repo with --user and --host" ' 1010 | repo_layer=( 1011 | "dotsdest/.dotdir1/" 1012 | "dotsdest/.dotfile1" 1013 | "dotsdest/.dotdir2/dotfile2" 1014 | ) 1015 | _make_layer "${repo_layer[@]}" 1016 | for i in "${repo_layer[@]}" 1017 | do 1018 | dotploy.sh add --host --user $i "dotsrepo" "dotsdest" 1019 | done 1020 | _test_expect_expr_true "test -d dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir1" 1021 | _test_expect_symlink "dotsdest/.dotdir1" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir1" 1022 | _test_expect_expr_true "test -f dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotfile1" 1023 | _test_expect_symlink "dotsdest/.dotfile1" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotfile1" 1024 | _test_expect_expr_true "test -f dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir2/dotfile2" 1025 | _test_expect_symlink "dotsdest/.dotdir2/dotfile2" "$TEST_FIELD/dotsrepo/__DOTDIR/__HOST.$HOST/__USER.$USER/.dotdir2/dotfile2" 1026 | ' 1027 | 1028 | _test_run "Add given file which is not in the dots dest" ' 1029 | repo_layer=( 1030 | ".dotdir1/" 1031 | ".dotfile1" 1032 | ".dotdir2/dotfile2" 1033 | ) 1034 | _make_layer "${repo_layer[@]}" 1035 | 1036 | output=$(dotploy.sh add ".dotdir1" "dotsrepo" "dotsdest" 2>&1) && echo "$output" 1037 | _test_expect_match "$output" "target not in dest home" 1038 | _test_expect_expr_true "test -d .dotdir1" 1039 | 1040 | output=$(dotploy.sh add ".dotfile1" "dotsrepo" "dotsdest" 2>&1) && echo "$output" 1041 | _test_expect_match "$output" "target not in dest home" 1042 | _test_expect_expr_true "test -f .dotfile1" 1043 | 1044 | output=$(dotploy.sh add ".dotdir2/dotfile2" "dotsrepo" "dotsdest" 2>&1) && echo "$output" 1045 | _test_expect_match "$output" "target not in dest home" 1046 | _test_expect_expr_true "test -f .dotdir2/dotfile2" 1047 | ' 1048 | 1049 | _test_run "Add given file to the dots repo with the target already exists" ' 1050 | repo_layer=( 1051 | "dotsdest/.dotdir1/" 1052 | "dotsrepo/__DOTDIR/.dotdir1/" 1053 | "dotsdest/.dotfile1" 1054 | "dotsrepo/__DOTDIR/.dotfile1" 1055 | "dotsdest/.dotdir2/dotfile2" 1056 | "dotsrepo/__DOTDIR/.dotdir2/dotfile2" 1057 | "dotsdest/.dotfile3" 1058 | "dotsrepo/__DOTDIR/.dotfile3" 1059 | ) 1060 | _make_layer "${repo_layer[@]}" 1061 | 1062 | output=$(dotploy.sh add "dotsdest/.dotdir1/" "dotsrepo" "dotsdest" 2>&1) && echo "$output" 1063 | _test_expect_match "$output" "target already exists" 1064 | _test_expect_expr_true "test -d dotsdest/.dotdir1" 1065 | 1066 | output=$(dotploy.sh add "dotsdest/.dotfile1" "dotsrepo" "dotsdest" 2>&1) && echo "$output" 1067 | _test_expect_match "$output" "target already exists" 1068 | _test_expect_expr_true "test -f dotsdest/.dotfile1" 1069 | 1070 | output=$(dotploy.sh add "dotsdest/.dotdir2/dotfile2" "dotsrepo" "dotsdest" 2>&1) && echo "$output" 1071 | _test_expect_match "$output" "target already exists" 1072 | _test_expect_expr_true "test -f dotsdest/.dotdir2/dotfile2" 1073 | 1074 | dotploy.sh add --force "dotsdest/.dotfile3" "dotsrepo" "dotsdest" 1075 | _test_expect_expr_true "test -h dotsdest/.dotfile3" 1076 | ' 1077 | 1078 | _test_run "Remove given file from linking to dots repo" ' 1079 | repo_layer=( 1080 | "dotsdest/.dotdir2/" 1081 | "dotsrepo/__DOTDIR/.dotdir1/" 1082 | "dotsrepo/__DOTDIR/.dotfile1" 1083 | "dotsrepo/__DOTDIR/.dotdir2/dotfile2" 1084 | ) 1085 | _make_layer "${repo_layer[@]}" 1086 | 1087 | ln -s $(realpath "dotsrepo/__DOTDIR/.dotdir1/") "dotsdest/.dotdir1" 1088 | dotploy.sh remove "dotsdest/.dotdir1" "dotsrepo" "dotsdest" 1089 | _test_expect_expr_true "test ! -h dotsdest/.dotdir1" 1090 | 1091 | ln -s $(realpath "dotsrepo/__DOTDIR/.dotfile1") "dotsdest/.dotfile1" 1092 | dotploy.sh remove "dotsdest/.dotfile1" "dotsrepo" "dotsdest" 1093 | _test_expect_expr_true "test ! -h dotsdest/.dotfile1" 1094 | 1095 | ln -s $(realpath "dotsrepo/__DOTDIR/.dotdir2/dotfile2") "dotsdest/.dotdir2/dotfile2" 1096 | dotploy.sh remove "dotsdest/.dotdir2/dotfile2" "dotsrepo" "dotsdest" 1097 | _test_expect_expr_true "test ! -h dotsdest/.dotdir2/dotfile2" 1098 | ' 1099 | 1100 | _test_run "Remove given file which is not a link" ' 1101 | repo_layer=( 1102 | "dotsdest/.dotdir1/" 1103 | "dotsrepo/__DOTDIR/.dotdir1/" 1104 | "dotsdest/.dotfile1" 1105 | "dotsrepo/__DOTDIR/.dotfile1" 1106 | "dotsdest/.dotdir2/dotfile2" 1107 | "dotsrepo/__DOTDIR/.dotdir2/dotfile2" 1108 | ) 1109 | _make_layer "${repo_layer[@]}" 1110 | 1111 | output=$(dotploy.sh remove "dotsdest/.dotdir1/" "dotsrepo" "dotsdest" 2>&1) && echo "$output" 1112 | _test_expect_match "$output" "target is not a link" 1113 | 1114 | output=$(dotploy.sh remove "dotsdest/.dotfile1" "dotsrepo" "dotsdest" 2>&1) && echo "$output" 1115 | _test_expect_match "$output" "target is not a link" 1116 | 1117 | output=$(dotploy.sh remove "dotsdest/.dotdir2/dotfile2" "dotsrepo" "dotsdest" 2>&1) && echo "$output" 1118 | _test_expect_match "$output" "target is not a link" 1119 | ' 1120 | 1121 | _test_run "Remove given file which is not in the dots dest" ' 1122 | repo_layer=( 1123 | ".dotdir2/" 1124 | "dotsrepo/__DOTDIR/.dotdir1/" 1125 | "dotsrepo/__DOTDIR/.dotfile1" 1126 | "dotsrepo/__DOTDIR/.dotdir2/dotfile2" 1127 | ) 1128 | _make_layer "${repo_layer[@]}" 1129 | 1130 | ln -s $(realpath "dotsrepo/__DOTDIR/.dotdir1/") ".dotdir1" 1131 | output=$(dotploy.sh remove ".dotdir1" "dotsrepo" "dotsdest" 2>&1) && echo "$output" 1132 | _test_expect_match "$output" "target not in dest home" 1133 | 1134 | ln -s $(realpath "dotsrepo/__DOTDIR/.dotfile1") ".dotfile1" 1135 | output=$(dotploy.sh remove ".dotfile1" "dotsrepo" "dotsdest" 2>&1) && echo "$output" 1136 | _test_expect_match "$output" "target not in dest home" 1137 | 1138 | ln -s $(realpath "dotsrepo/__DOTDIR/.dotdir2/dotfile2") ".dotdir2/dotfile2" 1139 | output=$(dotploy.sh remove ".dotdir2/dotfile2" "dotsrepo" "dotsdest" 2>&1) && echo "$output" 1140 | _test_expect_match "$output" "target not in dest home" 1141 | ' 1142 | 1143 | _test_run "Remove given file which is not linking to the dots repo" ' 1144 | repo_layer=( 1145 | ".dotdir1/" 1146 | ".dotfile1" 1147 | ".dotdir2/dotfile2" 1148 | "dotsdest/.dotdir2/" 1149 | "dotsrepo/__DOTDIR/.dotdir1/" 1150 | "dotsrepo/__DOTDIR/.dotfile1" 1151 | "dotsrepo/__DOTDIR/.dotdir2/dotfile2" 1152 | ) 1153 | _make_layer "${repo_layer[@]}" 1154 | 1155 | ln -s $(realpath ".dotdir1/") "dotsdest/.dotdir1" 1156 | output=$(dotploy.sh remove "dotsdest/.dotdir1/" "dotsrepo" "dotsdest" 2>&1) && echo "$output" 1157 | _test_expect_match "$output" "target not link to our repo" 1158 | 1159 | ln -s $(realpath ".dotfile1") "dotsdest/.dotfile1" 1160 | output=$(dotploy.sh remove "dotsdest/.dotfile1" "dotsrepo" "dotsdest" 2>&1) && echo "$output" 1161 | _test_expect_match "$output" "target not link to our repo" 1162 | 1163 | ln -s $(realpath ".dotdir2/dotfile2") "dotsdest/.dotdir2/dotfile2" 1164 | output=$(dotploy.sh remove "dotsdest/.dotdir2/dotfile2" "dotsrepo" "dotsdest" 2>&1) && echo "$output" 1165 | _test_expect_match "$output" "target not link to our repo" 1166 | ' 1167 | 1168 | _test_done 1169 | --------------------------------------------------------------------------------