aboutsummaryrefslogtreecommitdiff
path: root/utils/inst
blob: a32c36b48c3cc7afa3ac07d5ccb490a1bed9fd27 (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
133
134
135
136
137
138
139
140
141
# Functions used for interactive installation of new changes to running system
# vim: ft=sh

# Ask if given section should be installed
# First argument is name (take care not to use special characters for regulard
# expression) and second argument is a question
ask() {
	local ignore_file=".ignore-$(hostname)"
	[ -f "$ignore_file" ] && grep -q "^$1$" "$ignore_file" && return 1
	if $FORCE; then
		echo "\e[1;34m$2\e[0m"
		# Fall trough with 0 exit (always yes)
	else
		echo -e -n "\e[1;34m$2? (Y/n) \e[0m"
		local reply
		read -r reply
		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
		nvim -d "$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 "$1" ]; then
		echo "Missing file to be installed: $1" >&2
	fi
	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"
}