-
-
Notifications
You must be signed in to change notification settings - Fork 48
/
Copy pathunsnap
executable file
·362 lines (340 loc) · 14 KB
/
unsnap
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
#!/usr/bin/env bash
# unsnap - a tool to migrate away from snaps
# shellcheck disable=SC2129
function display_warnings() {
echo "WARNING! Care has been taken to ensure this script is safe."
echo "The generated scripts will remove applications and data."
echo "Please ensure you have backups in case you need to recover data."
echo "Also note significant disk space may be required to migrate,"
echo "while both snaps and equivalent flatpaks are installed."
read -r -p "Press enter now to continue or CTRL+C to abort."
}
function setup_environment() {
DATETIMESTAMP=$(date +%Y-%m-%d.%H.%M.%S)
LOGDIR="./log-$DATETIMESTAMP"
LOGFILE="$LOGDIR/unsnap.log"
INSTALLEDSNAPLIST="$LOGDIR/allsnaps.txt"
FILTEREDSNAPLIST="$LOGDIR/filteredsnaps.txt"
MISSINGFLATPAK="$LOGDIR/missingflatpak.txt"
APPLIST="./applist.csv"
EXCLUDEDSNAPLIST="./excluded_snaps.txt"
BACKUPSCRIPT="$LOGDIR/00-backup"
INSTALLFLATPACKSCRIPT="$LOGDIR/01-install-flatpak"
ENABLEFLATHUBSRIPT="$LOGDIR/02-enable-flathub"
INSTALLPACKAGESSCRIPT="$LOGDIR/03-install-flatpaks"
REMOVESNAPSSCRIPT="$LOGDIR/04-remove-snaps"
REMOVESNAPDSCRIPT="$LOGDIR/99-remove-snapd"
SHEBANG="#!/usr/bin/env bash"
RECOMMENDREBOOT="no"
REBOOTTEXT="WARNING: Please logout/in or reboot, to ensure applications appear in your desktop menu"
DISTRO="unknown"
}
function create_logdir() {
mkdir "$LOGDIR"
}
function audit_snap() {
# TODO: Change these to not require snap, but use a reliable API instead
if snap info "$1" > /dev/null 2>&1; then
RESULT="✔ "
else
RESULT="✖ "
fi
echo "INFO: $RESULT Audit snap $1" | tee -a "$LOGFILE"
}
function audit_flatpak() {
# Check if a flatpak exists in the currently configured remotes
# TODO: Change these to not require flatpak execution, but use a reliable API instead
if flatpak search "$1" > /dev/null; then
RESULT="✔ "
else
RESULT="✖ "
fi
echo "INFO: $RESULT Audit flatpak $1" | tee -a "$LOGFILE"
}
function check_applist() {
# Called by 'unsnap check'
# Iterates through the csv file containing mapping of snap,flatpak to see
# if the snap and flatpak actually exist on the snap store and flathub
# This should really only be used by developers of unsnap, to verify that the
# applist.csv data is sane/valid
while IFS="" read -r p || [ -n "$p" ]
do
snap=$(echo "$p" | awk -F ',' '{ print $1}')
flatpak=$(echo "$p" | awk -F ',' '{ print $2}')
audit_snap "$snap"
audit_flatpak "$flatpak"
done < "$APPLIST"
exit 0
}
function check_for_snap() {
# Check for the existence of a an executable snap binary.
# If snap doesn't exist or work, likelyhood is no snaps are installed either
# so we exit out.
echo "INFO: Checking for snap binary" | tee -a "$LOGFILE"
if [ -x "$(command -v snap)" ]; then
echo "INFO: snap found" | tee -a "$LOGFILE"
else
echo "ERROR: snapd doesn't appear to be installed, exiting." | tee -a "$LOGFILE"
exit 1
fi
echo "INFO: Check for any snaps installed" | tee -a "$LOGFILE"
if [ "$(snap list | wc -l)" == "0" ]; then
echo "ERROR: No snaps installed, nothing to do here!" | tee -a "$LOGFILE"
exit 6
fi
}
function generate_flatpak_install_script() {
# Generate shell script to install flatpak itself
# As flatpak binary may not be installed (especially on Ubuntu and some derivatives)
# TODO: We assume use of sudo here, which we really shouldn't, but instead tell user
# to run script using sudo or root.
echo "INFO: Generating flatpak installer script in $INSTALLFLATPACKSCRIPT" | tee -a "$LOGFILE"
echo "$SHEBANG" > "$INSTALLFLATPACKSCRIPT"
case $DISTRO in
debian|ubuntu|linuxmint|pop|elementary|zorin)
cat <<EOT >> "$INSTALLFLATPACKSCRIPT"
# Documentation: https://flatpak.org/setup/
sudo apt update
sudo apt install -y flatpak
# sudo apt install gnome-software-plugin-flatpak
EOT
;;
*)
echo "ERROR: Unable to generate flatpak install script. Unimplemented distro." | tee -a "$LOGFILE"
exit 5
esac
RECOMMENDREBOOT="yes"
echo "echo $REBOOTTEXT" >> "$INSTALLFLATPACKSCRIPT"
chmod +x "$INSTALLFLATPACKSCRIPT"
}
function generate_packages_install_script() {
# Generate shell script to install each flatpak in turn
# TODO: Should also wrap each install to detect if it fails, and stop to cope
# with error situations like disk full.
echo "INFO: Generating flatpaks installer script in $INSTALLPACKAGESSCRIPT" | tee -a "$LOGFILE"
echo "$SHEBANG" > "$INSTALLPACKAGESSCRIPT"
echo -n "for f in " >> "$INSTALLPACKAGESSCRIPT"
while IFS="" read -r p || [ -n "$p" ]
do
snap=$p
flatpak=$(grep "^$p" "$APPLIST" | awk -F ',' '{ print $2}')
if [ "$flatpak" == "" ]; then
echo "WARNING: No equivalent flatpak for $snap found" | tee -a "$LOGFILE"
echo "$snap" >> "$MISSINGFLATPAK"
else
echo -n "$flatpak " >> "$INSTALLPACKAGESSCRIPT"
fi
done < "$FILTEREDSNAPLIST"
echo -n " ;" >> "$INSTALLPACKAGESSCRIPT"
echo " do" >> "$INSTALLPACKAGESSCRIPT"
echo " flatpak install flathub --noninteractive -y \$f" >> "$INSTALLPACKAGESSCRIPT"
echo "done" >> "$INSTALLPACKAGESSCRIPT"
chmod +x "$INSTALLPACKAGESSCRIPT"
}
function generate_flathub_enablement_script() {
# Generate short script to enable flathub which is required if
# the user hasn't already enabled it as (currently) all the applications we
# install are from flathub - but this could change in the future.
# flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
echo "INFO: Generating flathub enablement script in $ENABLEFLATHUBSRIPT" | tee -a "$LOGFILE"
echo "$SHEBANG" > "$ENABLEFLATHUBSRIPT"
echo "sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo" >> "$ENABLEFLATHUBSRIPT"
chmod +x "$ENABLEFLATHUBSRIPT"
}
function generate_remove_snaps_script() {
# Generate a shell script to remove each snap in turn.
echo "INFO: Generating snap removal script in $REMOVESNAPSSCRIPT" | tee -a "$LOGFILE"
echo "$SHEBANG" > "$REMOVESNAPSSCRIPT"
echo -n "for s in " >> "$REMOVESNAPSSCRIPT"
# Iterate through the filtered list of snaps (that is snaps which aren't excluded from matching)
while IFS="" read -r p || [ -n "$p" ]
do
snap=$(echo "$p" | awk -F ',' '{ print $1}')
# Check to make sure the snap isn't on the missing list.
if grep "$snap" "$MISSINGFLATPAK"; then
echo "WARNING: $snap snap has no equivalent, not candidate for removing" | tee -a "$LOGFILE"
else
echo -n "$snap " >> "$REMOVESNAPSSCRIPT"
fi
done < "$FILTEREDSNAPLIST"
echo -n " ;" >> "$REMOVESNAPSSCRIPT"
echo " do" >> "$REMOVESNAPSSCRIPT"
echo " sudo snap remove \$s " >> "$REMOVESNAPSSCRIPT"
echo "done" >> "$REMOVESNAPSSCRIPT"
chmod +x "$REMOVESNAPSSCRIPT"
}
function generate_remove_snapd_script() {
# Generate shell script to remove snapd.
# Needs to use distro specific commands to do this via the appropriate
# package manager
# Note that currently we assume sudo, but for some distros, that won't work
# so we might be better off removing all references to sudo, and inform the user
# to run the script as "root user or sudo as appropriate".
echo "INFO: Generating snapd removal script in $REMOVESNAPDSCRIPT" | tee -a "$LOGFILE"
echo "$SHEBANG" > "$REMOVESNAPDSCRIPT"
echo "echo Removing snapd" >> "$REMOVESNAPDSCRIPT"
case $DISTRO in
debian|ubuntu|linuxmint|pop|elementary|zorin)
echo "sudo apt remove snapd" >> "$REMOVESNAPDSCRIPT"
;;
*)
echo "ERROR: Unable to generate snapd removal script. Unimplemented distro." | tee -a "$LOGFILE"
esac
chmod +x "$REMOVESNAPDSCRIPT"
}
function generate_backup_script() {
# Generate shell script which will use snap save to snapshot each application user data
# We snapshot all snaps, even if only some of them are being replaced, because the user
# might run the 'remove snapd' script, which will nuke all their snaps, not just migrated
# ones.
# Not all snaps store data in their own directory - classic snaps being a good culprit
echo "INFO: Generating snap backup script in $BACKUPSCRIPT" | tee -a "$LOGFILE"
echo "$SHEBANG" > "$BACKUPSCRIPT"
echo "# Documentation: https://snapcraft.io/docs/snapshots" >> "$BACKUPSCRIPT"
echo -n "sudo snap save " >> "$BACKUPSCRIPT"
while IFS="" read -r p || [ -n "$p" ]
do
snap=$(echo "$p" | awk -F ',' '{ print $1}')
echo -n "$snap " >> "$BACKUPSCRIPT"
done < "$FILTEREDSNAPLIST"
echo "" >> "$BACKUPSCRIPT"
chmod +x "$BACKUPSCRIPT"
}
function check_for_flatpak() {
# Check if the flatpak binary exists, and if it doesn't call
# function to generate a script to install flatpak
echo "INFO: Checking for flatpak binary" | tee -a "$LOGFILE"
if [ -x "$(command -v flatpak)" ]; then
echo "INFO: flatpak found no need to generate flatpak install script" | tee -a "$LOGFILE"
check_for_flathub
else
echo "INFO: flatpak doesn't appear to be installed, adding installer script and enabling flathub" | tee -a "$LOGFILE"
generate_flatpak_install_script
generate_flathub_enablement_script
fi
}
function check_for_flathub() {
# Check if flathub is a configured remote and if not, call function to
# generate a script which enables it.
echo "INFO: Checking for flathub remote" | tee -a "$LOGFILE"
if flatpak remotes | grep flathub > /dev/null; then
echo "INFO: flathub already enabled" | tee -a "$LOGFILE"
else
echo "INFO: flathub doesn't appear to be enabled" | tee -a "$LOGFILE"
generate_flathub_enablement_script
fi
}
function determine_distro() {
# Figure out what distro we're running on so we can use appropriate commands
# later for installing / removing snapd and installing flatpak
# TODO: Add more distros
CANDIDATE=$(grep -w ID /etc/os-release | awk -F "=" '{ print $2} ')
case $CANDIDATE in
debian|ubuntu|linuxmint|pop|elementary|zorin)
DISTRO="$CANDIDATE"
;;
*)
echo "ERROR: Running on unknown distro, '$CANDIDATE' aborting" | tee -a "$LOGFILE"
exit 2
;;
esac
echo "INFO: Detected $DISTRO" | tee -a "$LOGFILE"
}
function get_installed_snaps() {
# Get list of currently installed snaps on this machine
# Then filter out excluded snaps, for which we know there is no
# equivalent in flathub (such as platform / theme snaps)
echo "INFO! Getting list of installed snaps to $INSTALLEDSNAPLIST" | tee -a "$LOGFILE"
snap list | tail -n +2 | awk -F " " '{ print $1 }' > "$INSTALLEDSNAPLIST"
echo "INFO! Trimming list of installed snaps to $FILTEREDSNAPLIST" | tee -a "$LOGFILE"
grep -v -f "$EXCLUDEDSNAPLIST" "$INSTALLEDSNAPLIST" > "$FILTEREDSNAPLIST"
}
function cleanup() {
# Remove working files created during unsnap run
rm "$INSTALLEDSNAPLIST" "$FILTEREDSNAPLIST"
}
function run_scripts() {
# Run the actual scripts one by one, stopping on error
echo "INFO: Running backup" | tee -a "$LOGFILE"
if "$BACKUPSCRIPT"; then
echo "INFO: Backup finished" | tee -a "$LOGFILE"
else
echo "ERROR: Backup failed" | tee -a "$LOGFILE"
exit 10
fi
if test -f "$INSTALLFLATPACKSCRIPT"; then
echo "INFO: Installing flatpak" | tee -a "$LOGFILE"
if "$INSTALLFLATPACKSCRIPT"; then
echo "INFO: Installing flatpak finished" | tee -a "$LOGFILE"
else
echo "ERROR: Install flatpak failed" | tee -a "$LOGFILE"
exit 11
fi
else
echo "INFO: Skipping installing flatpak, already installed" | tee -a "$LOGFILE"
fi
if test -f "$ENABLEFLATHUBSRIPT"; then
echo "INFO: Enabling flathub" | tee -a "$LOGFILE"
if "$ENABLEFLATHUBSRIPT"; then
echo "INFO: Flathub enabled" | tee -a "$LOGFILE"
else
echo "ERROR: Enabling flathub failed" | tee -a "$LOGFILE"
exit 12
fi
else
echo "INFO: Skipping enabling flathub, already enabled" | tee -a "$LOGFILE"
fi
echo "INFO: Installing flatpak packages" | tee -a "$LOGFILE"
if "$INSTALLPACKAGESSCRIPT"; then
echo "INFO: flatpaks installed" | tee -a "$LOGFILE"
echo "INFO: These flatpaks are now installed:" | tee -a "$LOGFILE"
flatpak list | tee -a "$LOGFILE"
else
echo "ERROR: Failed to install flatpaks" | tee -a "$LOGFILE"
exit 13
fi
echo "INFO: Removing snaps" | tee -a "$LOGFILE"
if "$REMOVESNAPSSCRIPT"; then
echo "INFO: Snaps removed" | tee -a "$LOGFILE"
echo "WARNING: These snaps are still installed:" | tee -a "$LOGFILE"
snap list | tee -a "$LOGFILE"
else
echo "ERROR: Failed to remove snaps" | tee -a "$LOGFILE"
exit 14
fi
# echo "INFO: Removing snapd daemon" | tee -a "$LOGFILE"
# if "$REMOVESNAPDSCRIPT"; then
# echo "INFO: snapd removed" | tee -a "$LOGFILE"
# else
# echo "ERROR: Failed to remove snapd" | tee -a "$LOGFILE"
# exit 15
# fi
}
function recommend_reboot() {
if [ "$RECOMMENDREBOOT" == "yes" ]; then
echo "$REBOOTTEXT" | tee -a "$LOGFILE"
fi
}
setup_environment
if [ "$1" == "check" ]; then
create_logdir
echo "INFO: Check requested" | tee -a "$LOGFILE"
check_applist
else
display_warnings
create_logdir
fi
determine_distro
check_for_snap # this should be universal, so we can check for the binary earlier for check_snap
check_for_flatpak # this should be universal check maybe, so it can be checked in "check_flatpak"
get_installed_snaps
generate_backup_script
generate_packages_install_script
generate_remove_snaps_script
generate_remove_snapd_script
cleanup
if [ "$1" == "auto" ]; then
echo "INFO: Auto requested" | tee -a "$LOGFILE"
run_scripts
recommend_reboot
fi