forked from Botspot/pi-apps
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpkg-install
executable file
·412 lines (319 loc) · 18.5 KB
/
pkg-install
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
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
#!/bin/bash
{ #prevents errors if script was modified while in use
set -o pipefail #if any command within a pipe fails, make the whole pipe fail. Necessary for error-catching with reduceapt
DIRECTORY="$(readlink -f "$(dirname "$0")")"
trap "exit 1" TERM
export TOP_PID=$$
error() {
echo -e "\e[91m$1\e[39m" 1>&2
kill -w -s TERM $TOP_PID
exit 1
}
# $1 is a quotation-marked, space-seperated list of package names.
# $2 is name of the app being installed.
# Example usage: ~/pi-apps/pkg-install "gparted buffer expect" Arduino
# "package1 | package2" represents "package1 or package2" (whichever is available) for $1
source "${DIRECTORY}/api" || error "Failed to source $DIRECTORY/api."
PKG_LIST="$1" #quotation-marked, space-seperated list of package names to install
app="$(basename "$2")" #remove any slashes to just get program name
reduceapt() { #remove unwanted lines from apt output
grep -v "apt does not have a stable CLI interface.\|Reading package lists...\|Building dependency tree\|Reading state information...\|Need to get\|After this operation,\|Get:\|Fetched\|Selecting previously unselected package\|Preparing to unpack\|Unpacking \|Setting up \|Processing triggers for "
}
message_to_user() { #bright, attention-getting message to display to user
echo -e "\e[93m
▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼
$1
▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲
\e[39m"
}
apt_diagnose() { #Explain stdin-inputted apt errors to user and list ways to fix them
errors="$(cat /dev/stdin)"
#------------------------------------------
#repo issues below
#------------------------------------------
#check for 'E: The repository'
if echo "$errors" | grep -qF 'E: The repository' || echo "$errors" | grep -qF 'sources.list entry misspelt' || echo "$errors" | grep -qF 'component misspelt in' ;then
message_to_user "APT reported a faulty repository, and you must fix it before Pi-Apps will work.
To delete the repository:
Remove the relevant line from /etc/apt/sources.list file or delete one file in
the /etc/apt/sources.list.d folder.
sources.list requires root permissions to edit: sudo mousepad /path/to/file"
fi
#check for 'NO_PUBKEY'
if echo "$errors" | grep -qF 'NO_PUBKEY';then
echo -en "\e[93m
▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼
APT reported an unsigned repository. This script will try to repair it.
Waiting 10 seconds... Press Ctrl+C to cancel.\e[39m"
sleep 10
echo -e '\n\e[93mAttempting to sign unsigned repositories...\e[39m'
sudo -E apt update 2>&1 | sed -ne 's/.*NO_PUBKEY //p' | while read key; do if ! [[ ${keys[*]} =~ "$key" ]]; then sudo -E apt-key adv --keyserver hkp://pool.sks-keyservers.net:80 --recv-keys "$key"; keys+=("$key"); fi; done
if [ $? == 0 ];then
echo -e '\e[93mDone. Please try installing the same app again.\e[39m'
else
echo -e '\e[93mAutomatic repository signing failed. You must repair the faulty repository yourself.\e[39m'
fi
echo -e "\e[93m▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲\n\e[39m"
fi
# check for 'Could not resolve' or 'Failed to fetch'
if echo "$errors" | grep -qF 'Could not resolve' || echo "$errors" | grep -qF 'Failed to fetch' || echo "$errors" | grep -qF 'Temporary failure resolving' || echo "$errors" | grep -qF 'Network is unreachable' || echo "$errors" | grep -qF 'Internal Server Error' || echo "$errors" | grep -q '404 .*Not Found' ;then
message_to_user "APT reported an unresolvable repository.
Please check your Internet connection and try again."
fi
#check for 'is configured multiple times in'
if echo "$errors" | grep -qF 'is configured multiple times in' ;then
message_to_user "APT reported a double-configured repository, and you must fix it to fix Pi-Apps.
To delete the repository:
Remove the relevant line from /etc/apt/sources.list file or delete the file in
the /etc/apt/sources.list.d folder.
sources.list requires root permissions to edit: sudo mousepad /path/to/file"
fi
#check for "W: Conflicting distribution: "
if echo "$errors" | grep -qF "W: Conflicting distribution: " ;then
message_to_user "Dpkg, apt, and Pi-Apps will not work until you fix the conflicting repository.
Read the errors above, then look through /etc/apt/sources.list and /etc/apt/sources.list.d, making changes as necessary.
Perhaps doing a Google search for the exact error you received would help."
fi
#check for "Release file for <repo-url> is not valid yet"
if echo "$errors" | grep -q "Release file for .* is not valid yet" ;then
message_to_user "One or more repositories has a release file that becomes valid in the future.
Please look at the above errors to see how long you have to wait."
fi
#check for typo in sources.list and list.d
if echo "$errors" | grep -qF "The list of sources could not be read." ;then
message_to_user "One or more sources contain a typo. Before APT or Pi-Apps will work, you must look around in /etc/apt/sources.list and /etc/apt/sources.list.d and fix the typo."
fi
#check for "W: Did not understand pin type releace"
if echo "$errors" | grep -qF "Did not understand pin type" ;then
message_to_user "This error was not caused by Pi-Apps. Looks like there is a typo in your /etc/apt/sources.list"
fi
#------------------------------------------
#repo issues above, apt/dpkg issues below
#------------------------------------------
#check for "--fix-broken"
if echo "$errors" | grep -qF "\-\-fix\-broken" || echo "$errors" | grep -qF "needs to be reinstalled" ;then
message_to_user "APT reported a broken package, and you must fix it before Pi-Apps will work.
Please run this command: sudo apt --fix-broken install"
fi
#check for dpkg --configure -a
if echo "$errors" | grep -qF "dpkg --configure -a" ;then
message_to_user "Before dpkg, apt, or Pi-Apps will work, dpkg needs to repair your system.
Please run this command: sudo dpkg --configure -a"
fi
#check for "dpkg: error: fgets gave an empty string from '/var/lib/dpkg/triggers/File'"
if echo "$errors" | grep -qF "dpkg: error: fgets gave an empty string from" ;then
message_to_user "Something strange is going on with your system and dpkg won't work. This is not a bug in Pi-Apps.
Perhaps this link will help: https://askubuntu.com/questions/1293709/weird-error-when-trying-to-install-packages-with-apt"
fi
#check for insufficient space errors
if echo "$errors" | grep -qF "You don't have enough free space in" ;then
message_to_user "Package(s) failed to install because your system has insufficient disk space.
Please free up some space, then try again."
fi
#check for "Command line option --allow-releaseinfo-change is not understood"
if echo "$errors" | grep -qF "Command line option --allow-releaseinfo-change is not understood" ;then
message_to_user "The Debian Project recently upgraded from Buster to version Bullseye. As a result, all Raspberry Pi OS Buster users will receive APT errors saying the repositories changed from 'stable' to 'oldstable'.
This error broke pi-apps. To fix it, the Pi-Apps developers added something to the 'sudo apt update' command: --allow-releaseinfo-change.
This flag allows the repository migration to succeed, therefore allowing Pi-Apps to work again.
Unfortunately for you, your operating system is too old for apt to understand this flag we added. Please upgrade your operating system for a better experience. Raspbian Stretch is unsupported and many apps will not install.
Please flash your SD card with the latest release of Raspberry Pi OS: https://www.raspberrypi.org/software"
fi
#check for corrupted package: "lzma error: compressed data is corrupt"
if echo "$errors" | grep -qF "lzma error: compressed data is corrupt" ;then
message_to_user "A package failed to install because it appears corrupted.
Try installing the same app again and if the problem persists please reach out to the Pi-Apps developers."
fi
#------------------------------------------
#apt/dpkg issues above, package issues below
#------------------------------------------
#check for "installed <package-name> package post-installation script subprocess returned error exit status 10"
if echo "$errors" | grep -q "installed .* post-installation script subprocess returned error exit status 10" ;then
message_to_user "Some other package on your system is causing problems. As a result, dpkg and APT won't work properly.
Perhaps reinstalling the package would help?"
fi
#check for faulty dphys-swapfile package
if echo "$errors" | grep -qF "error processing package dphys-swapfile" ;then
message_to_user "Before dpkg, apt, or Pi-Apps will work, dphys-swapfile must be fixed.
Try Googling the above errors, or ask the Pi-Apps developers for help."
fi
#check for unconfigured boot-firmware package
if echo "$errors" | grep -qF "missing /boot/firmware, did you forget to mount it" || echo "$errors" | grep -q "u-boot-rpi" ;then
message_to_user "Package(s) failed to install because your boot drive is not working.
You must fix the u-boot-rpi package before dpkg, apt, or Pi-Apps will work."
fi
#check for "files list file for package 'package-name' is missing final newline"
if echo "$errors" | grep -q "files list file for package .* is missing final newline" ;then
message_to_user "Before dpkg, apt, or Pi-Apps will work, your system must be repaired.
Try Googling the above errors, or ask the Pi-Apps developers for help.
Perhaps this link will help: https://askubuntu.com/questions/909719/dpkg-unrecoverable-fatal-error-aborting-files-list-file-for-package-linux-ge"
fi
#check for "installed raspberrypi-kernel package post-installation script subprocess returned error exit status 1"
if echo "$errors" | grep -qF "raspberrypi-kernel package post-installation script subprocess returned error exit status" ;then
message_to_user "The raspberrypi-kernel package on your system is causing problems.
Pi-Apps, dpkg and APT won't work properly until the problem is fixed.
Google the errors above this message, or ask in the Raspberry Pi Forums.
https://www.raspberrypi.org/forums"
fi
#check for "raspberrypi-bootloader package pre-installation script subprocess returned error exit status 2"
if echo "$errors" | grep -qF "raspberrypi-bootloader package pre-installation script subprocess returned error exit status" ;then
message_to_user "The raspberrypi-bootloader package on your system is causing problems.
Pi-Apps, dpkg and APT won't work properly until the problem is fixed.
Google the errors above this message, or ask in the Raspberry Pi Forums.
https://www.raspberrypi.org/forums"
fi
#check for "dpkg: error processing package nginx-full (--configure):"
if echo "$errors" | grep -qF "error processing package nginx-full" ;then
message_to_user "This error was not caused by Pi-Apps, it is caused by your nginx-full package.
Maybe reinstalling it would help?
sudo apt install --reinstall nginx-full"
fi
#check for "installed libwine-development:arm64 package post-installation script subprocess returned error exit status 1"
if echo "$errors" | grep -qF "libwine-development:arm64 package post-installation script subprocess returned error exit status" ;then
message_to_user "This error was not caused by Pi-Apps, it is caused by your libwine-development package.
Maybe reinstalling it would help?
sudo apt install --reinstall libwine-development"
fi
#check for "installed firmware-microbit-micropython-dl package post-installation script subprocess returned error exit status 1"
if echo "$errors" | grep -qF "installed firmware-microbit-micropython-dl package post-installation script subprocess returned error exit status 1" ;then
message_to_user "This error was not caused by Pi-Apps, it is caused by your firmware-microbit-micropython-dl package.
Maybe reinstalling it would help?
sudo apt install --reinstall firmware-microbit-micropython-dl"
fi
#no need for this function to exit with return code 1 just because the last if statement evaluated as false
return 0
}
echo "Running pkg-install..."
if [ -z "$PKG_LIST" ];then
error "No package names specified to pkg-install!"
elif [ -z "$app" ];then
error "No app name specified to pkg-install!"
fi
IFS=$' \n'
apt_lock_wait
#sudo apt update
{
echo -e "Running \e[4msudo a\e[0mp\e[4mt u\e[0mp\e[4mdate\e[0m..."
output="$(sudo -E apt update --allow-releaseinfo-change 2>&1 | reduceapt | tee /dev/stderr)"
exitcode=$?
#inform user about autoremovable packages
if [ ! -z "$(echo "$output" | grep 'autoremove to remove them' )" ];then
echo -e "\e[33mSome packages are unnecessary.\e[39m Please consider running \e[4msudo apt autoremove\e[0m."
fi
#inform user packages are upgradeable
if [ ! -z "$(echo "$output" | grep 'packages can be upgraded' )" ];then
echo -e "\e[33mSome packages can be upgraded.\e[39m Please consider running \e[4msudo a\e[0mp\e[4mt full-u\e[0mpg\e[4mrade\e[0m."
elif [ ! -z "$(echo "$output" | grep 'package can be upgraded' )" ];then
echo -e "\e[33mOne package can be upgraded.\e[39m Please consider running \e[4msudo a\e[0mp\e[4mt full-u\e[0mpg\e[4mrade\e[0m."
fi
#exit on apt error
errors="$(echo "$output" | grep '^[(W)|(E)|(Err]:')"
if [ $exitcode != 0 ] || [ ! -z "$errors" ];then
echo -e "\e[91mpkg-install failed to run \e[4msudo apt update\e[0m\e[39m!"
echo -e "APT reported these errors:\n\e[91m$errors\e[39m"
#run some apt error diagnosis
echo "$output" | apt_diagnose
exit 1
fi
}
#workarounds for local debs
{
for package in $PKG_LIST ;do
#if package begins with / (absolute path)
if [[ "$package" == /* ]];then
#determine the package name from the package filepath
packagename="$(dpkg-deb -I "$package" | grep "^ Package:" | awk '{print $2}')"
[ -z "$packagename" ] && error "pkg-install: failed to determine the package name of $package"
#change PKG_LIST to contain package name instead of package's absolute path
PKG_LIST="$(echo "$PKG_LIST" | sed "s|$package|$packagename|")"
apt_lock_wait
echo -e "\e[97m\nInstalling local $packagename package...\e[39m"
#install it and reduce apt's output
output="$(sudo -E apt install -fy --no-install-recommends --allow-downgrades "$package" 2>&1 | reduceapt | tee /dev/stderr)"
if [ $? != 0 ];then
echo "$output" | apt_diagnose
error "pkg_install: While installing local packages, $package failed to install."
fi
sudo -E apt-mark auto "$packagename" || error "pkg-install: failed to mark the $packagename package as autoremovable.\nlocal package path: $package"
fi
done
#now PKG_LIST shouldn't contain any absolute file paths
if [[ "$PKG_LIST" == /* ]];then
error "pkg_install: failed to remove all absolute paths from the package list!\nContents of PKG_LIST:\n$PKG_LIST"
fi
}
#workarounds for regex (using '*')
{
for package in $PKG_LIST ;do
#if package contains *
if echo "$package" | grep -q '*' ;then
echo -e "\e[97m\n$package contains regex. Expanding it...\e[39m"
list="$(apt-cache search "$package" | awk '{print $1}' | grep "$(echo "$package" | tr -d '*')" | tr '\n' ' ')"
#change PKG_LIST to contain package name instead of package's absolute path
PKG_LIST="$(echo "$PKG_LIST" | sed "s|$(echo "$package" | sed 's/*/\\*/g')|$list|g")"
echo -e "\e[97m\npackage list is now: $PKG_LIST\e[39m"
fi
done
#now PKG_LIST shouldn't contain any * characters
if echo "$PKG_LIST" | grep -q '*';then
error "pkg_install: failed to remove all regex from the package list!\nContents of PKG_LIST:\n$PKG_LIST"
fi
}
#format PKG_LIST - remove double spaces, preceding spaces, and trailing spaces.
PKG_LIST="$(echo "$PKG_LIST" | sed 's/ / /g' | sed 's/^ //g' | sed 's/ $//g')"
#create dummy deb
{
#create dummy apt package that depends on the packages this app requires
echo -e "\e[97m\nCreating dummy deb...\e[39m"
#to avoid issues with symbols and spaces in app names, we shasum the app name for use in apt
appnamehash="$(echo "$app" | md5sum | cut -c1-8 | awk '{print $1}')"
rm -rf ~/pi-apps-$appnamehash ~/pi-apps-$appnamehash.deb
trap "rm -rf $HOME/pi-apps-$appnamehash $HOME/pi-apps-$appnamehash.deb" EXIT
mkdir -p ~/pi-apps-$appnamehash/DEBIAN
echo "Maintainer: Pi-Apps team
Name: $app
Description: Dummy package created by pi-apps to install dependencies for the '$app' app
Version: 1.0
Architecture: all
Priority: optional
Section: custom
Depends: $(echo "$PKG_LIST" | tr -d ',' | sed 's/ /, /g' | sed 's/, |/ |/g' | sed 's/|, /| /g')
Package: pi-apps-$appnamehash" > ~/pi-apps-$appnamehash/DEBIAN/control
#fix error report "dpkg-deb: error: control directory has bad permissions 700 (must be >=0755 and <=0775)"
sudo chmod -R '0755' ~/pi-apps-$appnamehash
output="$(dpkg-deb --build ~/pi-apps-$appnamehash 2>&1)"
if [ $? != 0 ];then
echo "$output"
echo "$output" | apt_diagnose
error "pkg-install: failed to create dummy deb pi-apps-$appnamehash"
fi
}
#install dummy deb
{
#ensure dummy deb isn't already installed
if dpkg -l pi-apps-$appnamehash &>/dev/null ;then
echo -e "\e[97m\nDummy deb is already installed. Uninstalling it first...\e[39m"
apt_lock_wait
output="$(sudo -E apt purge -y pi-apps-$appnamehash 2>&1 | reduceapt | tee /dev/stderr )"
if [ $? != 0 ];then
echo "$output" | apt_diagnose
error "Failed to purge dummy deb (pi-apps-$appnamehash)"
fi
#sudo -E apt update &>/dev/null
fi
apt_lock_wait
echo -e "\e[97m\nInstalling dummy deb...\e[39m"
output="$(sudo -E apt install -fy --no-install-recommends --allow-downgrades ~/pi-apps-$appnamehash.deb 2>&1 | reduceapt | tee /dev/stderr )"
rm -f ~/pi-apps-$appnamehash.deb
rm -rf ~/pi-apps-$appnamehash
echo -e "\e[97m\nApt finished.\e[39m"
errors="$(echo "$output" | grep '^[(W)|(E)|(Err]:')"
if [ ! -z "$errors" ];then
echo -e "\e[91mFailed to install the packages!\e[39m"
echo -e "APT reported these errors:\n\e[91m$errors\e[39m"
#run some apt error diagnosis
echo "$output" | apt_diagnose
exit 1
fi
exit 0
}
} #prevents errors if script was modified while in use