aboutsummaryrefslogtreecommitdiff
path: root/utils/inst
blob: e0a490eff14a018e382ea1c5102a4209cb0c4f63 (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
# Functions used for interactive installation of new changes to running system
# vim: ft=sh

ask() {
	if $FORCE; then
		echo -ne "\e[1;34m$1\e[0m"
		# Fall trough with 0 exit (always yes)
	else
		echo -ne "\e[1;34m$1? (Y/n) \e[0m"
		read
		[[ $REPLY =~ ^[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
}

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="${g#$1}"
			PREV="$(pwd)"
			cd "$2/$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 $2/$G"
			else
				echo -e "\e[0;32mCheckout of git repository:\e[0m $2/$G"
				# Checkout all files to HEAD
				git --work-tree=. checkout -f HEAD
				# Update all submodules
				git --work-tree=. submodule update
			fi
			cd "$PREV"
		done
	else
		dodiff "$1" "$2"
	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.
doinst() {
	echo -e "\e[1;34mrsync -rlpt $1 $2\e[0m"
	rsync -rlpt $1 $2
	# Now edit all .git files in target directory
	for g in `find "$2" -name '.git' -type f`; do
		if ! grep -q "gitdir: " "$g"; then
			continue # Probably not a git repository or who knows.
		fi
		echo -e "\e[1;34mPointing git repository $g to this repository\e[0m"
		echo gitdir: $PWD/.git`sed "s/^gitdir: [./]*git//" "$g"` > "$g"
	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"
}