-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsnap-to-flatpak.sh
More file actions
executable file
·321 lines (269 loc) · 12.4 KB
/
snap-to-flatpak.sh
File metadata and controls
executable file
·321 lines (269 loc) · 12.4 KB
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
#!/bin/bash
function print(){
# First, let's set the text on the teminal with bold text to make emphasis
tput bold
echo -e "$1" | tr --delete "\t"
#return the terminal to regular text
tput sgr0
}
# another function, this time is is for checking if the answer to a prompt is yes or no
function answer_affirmative(){
# we will check if the given answer (as a text string) matches some patterns, so we will use regular expressions.
# Affirmation can be answered by typing 'Y', 'y', 'Yes' and 'yes'. Any other option fails. First, we check if the text starts
# with either upper-case Y or lower-case y. Then we check if there is an 'es' followinfg the Y or not,
# and finally we check if we reached the end of the string (marked in regular expressions by a $)
[[ "$1" =~ [Yy](es)?$ ]]
}
# Let's start by issuing a warning in text, notification and sound
print "
----------------------------------------------
WARNING: ALL YOUR SNAPS WILL BE DELETED!!!!!!!
REPEAT: ALL YOUR SNAPS WILL BE DELETED!!!!!!!
----------------------------------------------
"
# ring 3 times the terminal by sending the bell character
for i in {1..3}
do
# -e tells echo to read the Escape special characters.
# -n tells it to not put a Newline after printing.
echo -e -n "\a"
# sleep for 0.2 seconds so rings are spaced
sleep .2
done
# prompt the user if they wish to continue
read -p "Are you sure [y/n]: " confirmation
# if the answer was negative, don't proceed and exit
if ! answer_affirmative $confirmation
then
print "\nOK, nothing was done.\n"
unset $confirmation
exit
fi
# unsetting variables (removing them) ensures no variables are left behind after the script.
# it is only a good practice, but not mandatory.
unset $confirmation
print "\nOK. Proceeding..."
print "\n--------------------------------------------------------------------------------\n"
print "FIRST STEP: Removing all the installed snaps"
# in order to process the snaps we get a list of all the snaps on the system and store it on a bash array.
# Because the command `snap list` puts at the first line a header for each field,
# we will filter out the first line using `tail` by telling it to start at the second line.
snaps=$(snap list | tail --lines +2 | cut --field 1 --delimiter " ")
# now some hoops to put all snaps in a proper bash array because `snaps`
# isn't a proper bash array (for some reason i don't know yet)
# create an empty bash array
declare -a snap_list=()
# go element by element on the snaps
for snap in $snaps
do
# and add them to the snaps array
snap_list+=($snap)
done
# save in a variable how many snaps we have by the count of elements in the snaps list array
snap_count=${#snap_list[@]}
# print the number and list of snaps installed
echo -e "\nCurrently $snap_count snaps are installed"
echo -e "The installed snaps are:\n${snap_list[@]}\n"
# save up the snap list in a text file next to where the scrip is running in case the user wants to consult it.
snap list > "$(pwd)/snap-list.txt"
print "The list of snaps has been saved into the text file '$(pwd)/snap-list.txt'\n"
# Now we are going through that array and remove each snap package from it.
# Snap doesn't let you remove a snap that is a dependency, and unfortunately,
# snaps doesn't offer an option (that I know) to list dependencies, so we are
# going to iterate over the array and try to remove each snap. If it was removed successfully,
# then we pop it out of the list and continue to the next, then we start all over again.
# I know this solution isn't efficient, but it is what I have for the moment.
# while the list of snaps isn't empty...
while [[ $snap_count -gt 0 ]]
do
# move an index in the range of elements on the snap list
for ((index=0; index<snap_count; index++))
do
# keep track of the snap we are working on currently in a variable with a name easier to read
current_snap=${snap_list[$index]}
# remove the snap indicated by the index, and discard the error message if it couldn't be removed
sudo snap remove --purge $current_snap 2> /dev/null
# if the last command was successful by exiting with status zero (meaning the snap could be removed)...
if [[ $? -eq 0 ]]
then # update the list of snaps by removing the one we just uninstalled
# create a new empty list for the updated snap list
declare -a new_snap_list=()
# iterate on each snap on the list
for snap in ${snap_list[@]}
do
# if the snap in the list isn't the one we just removed...
if [[ $snap != $current_snap ]]
then
# add the snap into the new list
new_snap_list+=($snap)
fi
done
# replace the old list with the updated one
snap_list=(${new_snap_list[@]})
# and update the count of snaps
snap_count=${#snap_list[@]}
fi
done
done
print "\nAll snap packages have been removed"
print "\n--------------------------------------------------------------------------------\n"
print "SECOND STEP: Removal of snap"
# Now we are going to remove snap by stopping it's services and then uninstalling it. Then we are going
# to tell APT to hold the package snapd, ignoring it from installations.
print "\nStopping snap services...\n"
# systemctl is the program that allows service management.
# stopping a service means halting it on the spot.
# the --show-transaction is only to make it more verbose
sudo systemctl stop snapd.socket --show-transaction
sudo systemctl stop snapd.service --show-transaction
sudo systemctl stop snapd.seeded.service --show-transaction
print "\nRemoving snap completely...\n"
# we use autoremove because it will also remove other related packages.
# the --purge options is for also removing configuration files,
# and the --assume-yes to do the uninstalling automatically instead of asking the user to confirm
sudo apt autoremove --purge snapd --assume-yes
print "\nMarking snap as a hold package so it cannot be reinstalled\n"
sudo apt-mark hold snapd
# now we are going to make some APT configuration files to avoid the installation of snap and
# the infamous firefox apt package that installs the snap version
print "\nGenerating APT configuration files\n"
# we use the tee program that takes some text as input and then prints it on the screen at the same time it writes that
# into a file. We use it because it can be called with elevated permissions (unlike >) and to show the contents of the config file to the user
# the package and pin-priority fielsds are quite self-explainatory, but the pin not so much.
# release means that the package comes from a given release of a distro.
# the a= parameter refers to the name of the archive of that release. '*'' refers to all.
# the o= parameter refers to the origin of a package (who makes it). 'Ubuntu*' referes to things packaged by Ubuntu.
echo -e "generating file '/etc/apt/preferences.d/no-snap-please' with the following contents:\n"
echo "Package: snapd
Pin: release a=*
Pin-Priority: -1" | sudo tee /etc/apt/preferences.d/no-snap-please
echo -e "\nGenerating the file '/etc/apt/preferences.d/no-firefox-snap-please' with the following contents:\n"
echo "Package: firefox*
Pin: release o=Ubuntu*
Pin-Priority: -1" | sudo tee /etc/apt/preferences.d/no-firefox-snap-please
print "\nUpdate APT repos so changes take effect\n"
sudo apt update
print "\nSnap removed"
print "\n--------------------------------------------------------------------------------\n"
print "THIRD STEP: Directory cleanup"
# Now we are going to remove files left by snaps.
# It is easier to make a list of possible directories than trying to search them dynamically.
# Contributors: feel free to add others that I missed.
# let's create a list of the directories to be removed
declare -a directories=("$HOME/snap" "/snap" "/var/snap" "/var/lib/snap" "/var/cache/snapd" "/usr/lib/snapd")
# iterate on each directory on the list of directories...
for directory in ${directories[@]}
do
# if the path we are looking up exist in the filesystem as a directory...
if [[ -d $directory ]]
then
# ...ask the user if they want to remove the directory and it's contents completely
echo ""
read -p "Do you want to completely remove the directory $directory? [y/n]: " rm_confirmation
# check the user's answer and either do nothing or proceed with the removal
if answer_affirmative $rm_confirmation
then # answer was affirmative. Remove the directory completely
print "\nRemoving $directory\n"
# --recursive tells rm to get inside each subdirectory and remove everything inside
# --force tells rm to don't ask about removing a file and Forces it's removal
# --verbose tells rm to print each thing it deletes.
sudo rm --recursive --force --verbose "$directory"
else
# answer was negative. Don't remove the directory
print "\nOK. $directory is left untouched\n"
fi
unset $rm_confirmation
fi
done
print "\nFiles removed"
print "\n--------------------------------------------------------------------------------\n"
print "FOURTH STEP: installing and setting up Flatpak"
# Here I'm simply following what it says on https://flatpak.org/setup/Ubuntu
print "\nInstalling flatpak and setting up Flathub repository...\n"
sudo apt install flatpak --assume-yes
sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
# we are going to detect if the user has a GUI app store compatible with Flatpak
# (currently only GNOME Software and KDE's Discover support flatpak).
# If the user does not have neither installed, a prompt suggesting them will appear.
# detect if gnome-software or plasma-discover is already installed:
# the `command` command is for running stuff that is not bash functions, but if
# we pass the -v flag instead it prints the path where the program lives, and nothing if not found.
# then we check with -x if that path is an executable file. If all is correct, we have found our app store.
if [[ -x $(command -v gnome-software) ]]
then
appstore="GNOME"
elif [[ -x $(command -v plasma-discover) ]]
then
appstore="KDE"
else
appstore="none"
fi
# launch the prompt in case we didn't find a suitable app store
if [[ $appstore == "none" ]]
then
print "\nYou can install flatpaks with the terminal, but there is the option
of using a graphical App Store to do it more comfortably.\n"
# ask the user if they want to install an app store
read -p "Do you want to install an App Store program? [y/n]: " use_appstore
# check the answer to see if we proceed with the app store selection or not.
if answer_affirmative $use_appstore
then
print "\nThe options are GNOME Software and KDE Discover
if you don't have an idea of what to choose:
KDE Discover works best if you use Qt-Based desktops:
• KDE Plasma (Kubuntu, Ubuntu Studio)
• LXQt (Lubuntu)
GNOME Software for GTK-based desktops (pretty much everything else):
• GNOME (regular Ubuntu, Edubuntu)
• Budgie (Ubuntu Budgie)
• Cinnamon (Ubuntu Cinnamon)
• MATE (Ubuntu Mate, Kylin)
• Unity (Ubuntu Unity)
• Xfce (Xubuntu)
You are free to choose whichever you want and make a mix."
# prompt the user with the choices of app store available as numbers
print "\nSelect the number of the App Store you would like to have:"
select appstore_to_install in GNOME-Software KDE-Discover
# install the app store the user selected based on it's answer
do
case $appstore_to_install in
"GNOME-Software")
print "\nOK. Installing GNOME Software...\n"
sudo apt install gnome-software --assume-yes
appstore="GNOME"
break
;;
"KDE-Discover")
print "\nOK. Installing KDE Discover...\n"
sudo apt install plasma-discover --assume-yes
appstore="KDE"
break
;;
*) # the user didn't select a number that corresponds with a valid choice
echo "That is not an option!"
;;
esac
done
else # the user said no to installing an app store
print "\nOK then. No GUI app will be installed."
fi
fi
#install the corresponding backend for flatpaks for the installed app store
# check if there is even an app store to work with in the first place
if [[ $appstore != "none" ]]
then
print "\nInstalling the corresponding flatpak backend for $appstore...\n"
if [[ $appstore == "GNOME" ]]
then
sudo apt install gnome-software-plugin-flatpak --assume-yes
elif [[ $appstore == "KDE" ]]
then
sudo apt install plasma-discover-backend-flatpak --assume-yes
fi
fi
unset $appstore
# finally, tell the user we have finished
print "\nWe are done! snap is no more, and flatpak is in.
check the list of the apps that were installed as snap in case
you want them reinstalled in flatpak/apt format, like Firefox.
Now, restart your computer to finish the setup of Flatpak"