aboutsummaryrefslogtreecommitdiff
path: root/utils/inst
blob: 9987fff88429ac1310ea8236d8646a04c82a346b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# Functions used for interactive installation of new changes to running system
# vim: ft=sh

ask() {
	if $FORCE; then
		echo -e "\e[1;34m$1\e[0m"
		# Fall trough with 0 exit (always yes)
	else
		echo -e -n "\e[1;34m$1? (Y/n) \e[0m"
		read
		echo "$REPLY" | grep -qE '^[Yy]?$'
	fi
}

dodiff() {
	if [ -d "$2" ]; then
		# If we just copying some file to directory
		OUT=$2/$(basename "$1")
	else
		OUT=$2
	fi
	if ! [ -f "$OUT" ]; then
		echo -e "\e[1;33mNot installed:\e[0m $1 => $OUT"
		if ask "Install?"; then
			doinst "$1" "$OUT"
		fi
		return
	fi
	if cmp "$1" "$OUT" >/dev/null 2>&1; then
		echo -e "\e[1;32mNo difference detected:\e[0m $OUT"
		return
	fi
	if $FORCE; then
		doinst "$1" "$OUT"
	else
		vimdiff "$1" "$OUT"
	fi
}

# Managing two git trees with master has small inconvenience that git allows only
# single branch checkout in all work trees, so as it sets now git will execute all
# commands not on deployed tree but on tree in this repository, so we need specify
# work tree on command line every time we want target deployed work tree.
gitrepo_relink() {
	local GITD="gitdir: $PWD/.git$(sed "s/^gitdir: [./]*git//" "$1")"
	# We check that we are pointing to correct path just because of making message correct
	if ! grep -q "$GITD" "$2"; then
		echo -e "\e[1;34mPointing git repository $2 to this repository\e[0m"
		echo "$GITD" > "$2"
	fi
	# else probably not a git repository or who knows.
}

checkdiff() {
	# Iterate trough source directory but ignore any git repositories
	# Note that it's design decision to not iterate trough target directory.
	if [ -d "$1" ]; then
		# This is check if we have correct inst command basically. If it is
		# directory than it have to have trailing slash to ensure that no
		# additional directory is created.
		if ! echo "$1" | grep -qE '/$'; then
			echo -e "\e[1;31mERROR: Directory without trailing slash detected:\e[0m $1"
			exit 1
		fi
		# Got trough all files ignoring git repositories
		for f in `find "$1" \( -type d -exec test -e '{}'/.git \; \) -prune -o -type f -print`; do
			F="${f#$1}"
			dodiff "$1/$F" "$2/$F"
		done
		# Check if we have all directories ignoring those in git repositories
		for d in `find "$1" -type d -print -exec test -e '{}'/.git \; -prune`; do
			D="${d#$1}"
			if [ ! -d "$2/$D" ]; then
				echo -e "\e[1;33mDirectory not installed:\e[0m $1/$D => $2/$D"
				if ask "Install?"; then
					doinst "$1/$D/" "$2/$D"
				fi
			fi
		done
		# Now checkout git repositories
		for g in `find "$1" -type d -exec test -e '{}'/.git \; -print -prune`; do
			G="$2/${g#$1}"
			gitrepo_relink "$g/.git" "$G/.git" # Always reling .git just to be sure
			PREV="$(pwd)"
			cd "$G"
			# Check if we have any change at all
			if git --work-tree=. diff --exit-code -s; then
				echo -e "\e[1;32mNo difference detected in git:\e[0m $G"
			else
				echo -e "\e[0;32mCheckout of git repository:\e[0m $G"
				# Checkout all files to HEAD
				git --work-tree=. checkout -f HEAD
				# Update all submodules
				git --work-tree=. submodule update --recursive
			fi
			cd "$PREV"
		done
	else
		dodiff "$1" "$2"
	fi
}

doinst() {
	echo -e "\e[1;34mrsync -rlpt $1 $2\e[0m"
	mkdir -p "$(dirname "$2")"
	rsync -rlpt $1 $2
	# Now edit all .git files in target directory
	for g in `find "$1" -name '.git' -type f`; do
		gitrepo_relink "$g" "$2/${g#$1}"
	done
}

inst() {
	if [ -e "$2" ]; then
		# If output exists, execute diff instead
		checkdiff $1 $2
		return
	fi
	doinst $1 $2
}

# gpg encrypted install
ginst() {
	if [ -z "$PASS" ]; then
		PASS="$(gpg --batch --decrypt pass.gpg)"
	fi
	# TODO probably we should be sure that file will be always removed
	local TMP="$(mktemp myconfigs.XXXXXXXXXX)"
	gpg --batch --passphase "$PASS" --output "$TMP" --decrypt "$1"
	inst "$TMP" "$2"
	gpg --batch --passphase "$PASS" --output "$1" --encrypt "$TMP"
}