aboutsummaryrefslogtreecommitdiffhomepage
path: root/installer.sh
blob: 4a8671e476a98469fe262d8f93db9b5f8831fc40 (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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
#!/bin/bash
# shellcheck disable=SC1117

################################################ SETUP ################################################
dependencies=(
	libasound2-dev
	libevdev-dev
	liblua5.3-dev
	libjack-jackd2-dev
	pkg-config
	libssl-dev
	python3-dev
	gcc
	make
	wget
	git
)
# Replace this with 'root' to bypass the user check
user="$(whoami)"
# Temporary directory used for repository clone
tmp_path="$(mktemp -d)"
# Installer/updater install directory
updater_dir="/etc/midimonster-updater"

latest_version="$(curl --silent "https://api.github.com/repos/cbdevnet/midimonster/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')"

# make invocation arguments
makeargs="all"

normal="$(tput sgr0)"
dim="$(tput dim)"
bold="$(tput bold)"
uline="$(tput smul)"
c_red="$(tput setaf 1)"
c_green="$(tput setaf 2)"
c_mag="$(tput setaf 5)"

DEFAULT_PREFIX="/usr"
DEFAULT_PLUGINPATH="/lib/midimonster"
DEFAULT_CFGPATH="/etc/midimonster/midimonster.cfg"
DEFAULT_EXAMPLES="/share/midimonster"

############################################## FUNCTIONS ##############################################
assign_defaults(){
	VAR_PREFIX="${VAR_PREFIX:-$DEFAULT_PREFIX}"
	VAR_PLUGINS="${VAR_PLUGINS:-$VAR_PREFIX$DEFAULT_PLUGINPATH}"
	VAR_DEFAULT_CFG="${VAR_DEFAULT_CFG:-$DEFAULT_CFGPATH}"
	VAR_EXAMPLE_CFGS="${VAR_EXAMPLE_CFGS:-$VAR_PREFIX$DEFAULT_EXAMPLES}"
}

ARGS(){
	for i in "$@"; do
		case "$i" in
			--prefix=*)
				VAR_PREFIX="${i#*=}"
			;;
			--plugins=*)
				VAR_PLUGINS="${i#*=}"
			;;
			--defcfg=*)
				VAR_DEFAULT_CFG="${i#*=}"
			;;
			--examples=*)
				VAR_EXAMPLE_CFGS="${i#*=}"
			;;
			--dev)
				NIGHTLY=1
			;;
			-d|--default)
				assign_defaults
			;;
			-fu|--forceupdate)
				UPDATER_FORCE="1"
			;;
			--install-updater|--selfupdate)
				NIGHTLY=1 prepare_repo
				install_script
				exit 0
			;;
			--install-dependencies)
				install_dependencies "${dependencies[@]}"
				exit 0
			;;
			-h|--help|*)
				assign_defaults
				printf "%sUsage: %s[OPTIONS]%s" "${bold}" "${normal} ${0} ${c_green}" "${normal}"
				printf "\n\t%s--prefix=%s<path>%s\t\tSet the installation prefix.\t\t%sDefault:%s" "${c_green}" "${normal}${c_red}" "${normal}" "${c_mag}" "${normal} ${dim}$VAR_PREFIX${normal}"
				printf "\n\t${c_green}--plugins=${normal}${c_red}<path>${normal}\tSet the plugin install path.\t\t${c_mag}Default:${normal} ${dim}%s${normal}" "$VAR_PLUGINS"
				printf "\n\t${c_green}--defcfg=${normal}${c_red}<path>${normal}\t\tSet the default configuration path.\t${c_mag}Default:${normal} ${dim}%s${normal}" "$VAR_DEFAULT_CFG"
				printf "\n\t${c_green}--examples=${normal}${c_red}<path>${normal}\tSet the path for example configurations.\t${c_mag}Default:${normal} ${dim}%s${normal}\n" "$VAR_EXAMPLE_CFGS"
				printf "\n\t%s--dev%s\t\t\tInstall nightly version." "${c_green}" "${normal}"
				printf "\n\t%s-d,\t--default%s\tUse default values to install." "${c_green}" "${normal}"
				printf "\n\t%s-fu,\t--forceupdate%s\tForce the updater to update without a version check." "${c_green}" "${normal}"
				printf "\n\t%s--selfupdate%s\t\tUpdates this script to the newest version and exit." "${c_green}" "${normal}"
				printf "\n\t%s--install-updater%s\tInstall the updater (Run with midimonster-updater) and exit." "${c_green}" "${normal}"
				printf "\n\t%s--install-dependencies%s\tInstall dependencies and exit" "${c_green}" "${normal}"
				printf "\n\t%s-h,\t--help%s\t\tShow this message and exit." "${c_green}" "${normal}"
				printf "\n\t%sEach argument can be overwritten by another, the last one is used!.%s\n" "${uline}${bold}${c_mag}" "${normal}"
				rmdir "$tmp_path"
				exit 0
			;;
		esac
		shift
	done
}

# Install unmatched dependencies
install_dependencies(){
	DEBIAN_FRONTEND=noninteractive apt-get update -y -qq > /dev/null || error_handler "There was an error doing apt update."
#	unset "$deps"
	for dependency in "$@"; do
		if [ "$(dpkg-query -W -f='${Status}' "$dependency" 2>/dev/null | grep -c "ok installed")" -eq 0 ]; then
			deps+=("$dependency")   # Add not installed dependency to the "to be installed array".
		else
			printf "%s already installed!\n" "$dependency"   # If the dependency is already installed print it.
		fi
	done

if [ ! "${#deps[@]}" -ge "1" ]; then    # If nothing needs to get installed don't start apt.
	printf "\nAll dependencies are fulfilled!\n"    # Dependency array empty! Not running apt!
else
	printf "\nThen following dependencies are going to be installed:\n"    # Dependency array contains items. Running apt.
	printf "\n%s\n" "${deps[@]}" | sed 's/ /, /g'
	DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-suggests --no-install-recommends "${deps[@]}" > /dev/null || error_handler "There was an error doing dependency installation."
	printf "\nAll dependencies are installed now!\n"    # Dependency array empty! Not running apt!
fi
	printf "\n"
}

ask_questions(){	
	# Only say if necessary
	if [ -z "$VAR_PREFIX" ] || [ -z "$VAR_PLUGINS" ] || [ -z "$VAR_DEFAULT_CFG" ] || [ -z "$VAR_EXAMPLE_CFGS" ]; then
		printf "%sIf you don't know what you're doing, just hit enter a few times.%s\n\n" "${bold}" "${normal}"
	fi
	
	if [ -z "$VAR_PREFIX" ]; then
		read -r -e -i "$DEFAULT_PREFIX" -p "PREFIX (Install root directory): " input
		VAR_PREFIX="${input:-$VAR_PREFIX}"
	fi

	if [ -z "$VAR_PLUGINS" ]; then
		read -r -e -i "$VAR_PREFIX$DEFAULT_PLUGINPATH" -p "PLUGINS (Plugin directory): " input
		VAR_PLUGINS="${input:-$VAR_PLUGINS}"
	fi

	if [ -z "$VAR_DEFAULT_CFG" ]; then
		read -r -e -i "$DEFAULT_CFGPATH" -p "Default config path: " input
		VAR_DEFAULT_CFG="${input:-$VAR_DEFAULT_CFG}"
	fi

	if [ -z "$VAR_EXAMPLE_CFGS" ]; then
		read -r -e -i "$VAR_PREFIX$DEFAULT_EXAMPLES" -p "Example config directory: " input
		VAR_EXAMPLE_CFGS="${input:-$VAR_EXAMPLE_CFGS}"
	fi
}

# Clone the repository and select the correct version
prepare_repo(){
	printf "Cloning the repository\n"
	git clone "https://github.com/cbdevnet/midimonster.git" "$tmp_path"
	printf "\n"

	# If not set via argument, ask whether to install development build
	if [ -z "$NIGHTLY" ]; then
		read -r -p "Do you want to install the latest development version? (y/n)? " magic
		case "$magic" in
			y|Y)
				printf "OK! You´re a risky person ;D\n\n"
				NIGHTLY=1
				;;
			n|N)
				printf "That´s OK - installing the latest stable version for you ;-)\n\n"
				NIGHTLY=0
				;;
			*)
				printf "%sInvalid input -- INSTALLING LATEST STABLE VERSION!%s\n\n" "${bold}" "${normal}"
				NIGHTLY=0
				;;
		esac
	fi

	# Roll back to last tag if a stable version was requested
	if [ "$NIGHTLY" != 1 ]; then
		cd "$tmp_path" || error_handler "Error doing cd to $tmp_path"
		printf "Finding latest stable version...\n"
		last_tag=$(git describe --abbrev=0)
		printf "Checking out %s...\n" "$last_tag"
		git checkout -f -q "$last_tag"
	fi
	printf "\n"
}

# Build and install the software
build(){
	# Export variables for make
	export PREFIX="$VAR_PREFIX"
	export PLUGINS="$VAR_PLUGINS"
	export DEFAULT_CFG="$VAR_DEFAULT_CFG"
	export EXAMPLES="$VAR_EXAMPLE_CFGS"

	cd "$tmp_path" || error_handler "Error doing cd to $tmp_path"
	make clean
	make "$makeargs"
	make install
}

# Save data for the updater
save_config(){
	rm -f "$updater_dir/updater.conf"
	mkdir -p "$updater_dir"	
	printf "Exporting updater config\n"
	printf "VAR_PREFIX=%s\nVAR_PLUGINS=%s\nVAR_DEFAULT_CFG=%s\nVAR_DESTDIR=%s\nVAR_EXAMPLE_CFGS=%s\n" "$VAR_PREFIX" "$VAR_PLUGINS" "$VAR_DEFAULT_CFG" "$VAR_DESTDIR" "$VAR_EXAMPLE_CFGS" > "$updater_dir/updater.conf"
}

# Updates this script using the one from the checked out repo (containing the requested version)
install_script(){
	mkdir -p "$updater_dir"
	printf "Copying updater to %s/updater.sh\n" "$updater_dir"
	cp "$tmp_path/installer.sh" "$updater_dir/updater.sh"
	chmod +x "$updater_dir/updater.sh"
	printf "Creating symlink /usr/bin/midimonster-updater\n"
	ln -s "$updater_dir/updater.sh" "/usr/bin/midimonster-updater"
}

error_handler(){
	[[ -n $1 ]] && printf "\n%s\n" "$1"
	printf "\nAborting"
	for i in {1..3}; do sleep 0.3s && printf "." && sleep 0.2s; done
	printf "\n"
	exit "1"
}

cleanup(){
	if [ -d "$tmp_path" ]; then
		printf "Cleaning up temporary files...\n"
		rm -rf "$tmp_path"
	fi
}

################################################ Main #################################################
trap error_handler SIGINT SIGTERM
trap cleanup EXIT

# Parse arguments
ARGS "$@"
clear

# Check whether we have the privileges to install stuff
if [ "$user" != "root" ]; then
	printf "The installer/updater requires root privileges to install the midimonster system-wide\n"
	exit 1
fi

# Check if we can download the sources
if [ "$(wget -q --spider http://github.com)" ]; then
	printf "The installer/updater requires internet connectivity to download the midimonster sources and dependencies\n"
	exit 1
fi

# Check whether the updater needs to run
if [ -f "$updater_dir/updater.conf" ] || [ "$UPDATER_FORCE" = "1" ]; then
	if [ -f "$updater_dir/updater.conf" ]; then
		# shellcheck source=/dev/null
		. "$updater_dir/updater.conf"
		# Parse arguments again to compensate overwrite from source
		ARGS "$@"
		printf "Imported settings from %s/updater.conf\n" "$updater_dir"
	fi

	if [ -n "$UPDATER_FORCE" ]; then
		printf "Forcing the updater to start...\n\n"
	elif [ -x "$VAR_PREFIX/bin/midimonster" ]; then
		installed_version="$(midimonster --version)"
		if [[ "$installed_version" =~ $latest_version ]]; then
			printf "The installed version %s seems to be up to date\nDoing nothing\n\n" "${bold}$installed_version${normal}"
			exit 0
		else
			printf "The installed version %s does not match the latest version %s\nMaybe you are running a development version?\n\n" "${bold}$installed_version${normal}" "${bold}$latest_version${normal}"
		fi
	fi

	# Run updater steps
	prepare_repo
	install_script
	save_config
	build
else
	# Run installer steps
	install_dependencies "${dependencies[@]}"
	prepare_repo
	ask_questions
	install_script
	save_config
	build
fi
exit 0