Skip to content

Commit 1e79261

Browse files
authored
Save Desktop v3.8.1 (#476)
2 parents 59eba91 + 6f5d565 commit 1e79261

File tree

6 files changed

+101
-57
lines changed

6 files changed

+101
-57
lines changed

meson.build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
project('savedesktop',
2-
version: '3.8',
2+
version: '3.8.1',
33
meson_version: '>= 1.0.0',
44
default_options: [ 'warning_level=2', 'werror=false', ],
55
)

po/savedesktop.pot

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ msgstr ""
255255

256256
#: src/gui/window.py
257257
msgid ""
258-
"<big><b>{}</b></big>\nYou can log out of the system for the changes to take effect, or go back to the previous page and log out later.\n"
258+
"<big><b>{}</b></big>\nYou can log out of the system for the changes to take effect, or go back to the previous page and log out later.\n\n<i>If your archive contains Flatpak apps, they will start installing after the next login.</i>"
259259
msgstr ""
260260

261261
#: src/gui/window.py

src/core/archive.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,6 @@ def start_saving(self):
5050
else:
5151
self._create_archive()
5252

53-
print("Moving the configuration archive to the user-defined directory")
54-
shutil.copyfile('cfg.sd.zip', self.path_with_filename)
55-
5653
print("Configuration saved successfully.")
5754
remove_temp_file()
5855

@@ -65,7 +62,7 @@ def _copy_config_to_folder(self):
6562

6663
# Create a new ZIP archive with 7-Zip
6764
def _create_archive(self):
68-
cmd = ['7z', 'a', '-tzip', '-mx=3', '-x!*.zip', '-x!saving_status', 'cfg.sd.zip', '.']
65+
cmd = ['7z', 'a', '-snL', '-mx=3', '-x!*.zip', '-x!saving_status', 'cfg.sd.zip', "."]
6966
if settings["enable-encryption"] or os.path.exists(f"{CACHE}/pb"):
7067
if password:
7168
cmd.insert(4, "-mem=AES256")
@@ -80,6 +77,9 @@ def _create_archive(self):
8077
else:
8178
print("7z finished with warnings:", proc.stderr)
8279

80+
print("Moving the configuration archive to the user-defined directory")
81+
shutil.copyfile('cfg.sd.zip', self.path_with_filename)
82+
8383
class Unpack:
8484
def __init__(self, dir_path):
8585
self.path_with_filename = dir_path
@@ -141,11 +141,24 @@ def _unpack_zip_archive(self):
141141
raise ValueError(first_error or "Wrong password")
142142
print("Checking password is completed.")
143143

144-
cmd = subprocess.run(
145-
['7z', 'x', '-y', f'-p{password}', self.path_with_filename, f'-o{TEMP_CACHE}'],
146-
capture_output=True, text=True, check=True
144+
cmd = ['7z', 'x', '-y', '-snL']
145+
146+
if password:
147+
cmd.append(f'-p{password}')
148+
149+
cmd.extend([
150+
self.path_with_filename,
151+
f'-o{TEMP_CACHE}'
152+
])
153+
154+
proc = subprocess.run(
155+
cmd,
156+
capture_output=True,
157+
text=True
147158
)
148-
print(cmd.stdout)
159+
160+
if proc.returncode >= 7:
161+
raise OSError(proc.stderr)
149162

150163
def __handle_sync_error(self):
151164
# If 7-Zip returns an error regarding an incorrect password and the {CACHE}/sync file

src/core/de_config.py

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import os, shutil, argparse
1+
import os, shutil, argparse, subprocess
22
from gi.repository import GLib
33
from savedesktop.globals import *
4+
from pathlib import Path
45

56
# Helping functions
67
def safe_copy(src: str, dst: str):
@@ -17,7 +18,7 @@ def safe_copy(src: str, dst: str):
1718
def safe_copytree(src: str, dst: str, ignore=None):
1819
if os.path.isdir(src):
1920
try:
20-
shutil.copytree(src, dst, dirs_exist_ok=True, ignore=ignore)
21+
shutil.copytree(src, dst, dirs_exist_ok=True, symlinks=True, ignore=ignore)
2122
print(f"[OK] Copied dir: {src}{dst}")
2223
except Exception as e:
2324
print(f"[ERR] Dir copy failed {src}{dst}: {e}")
@@ -45,6 +46,9 @@ def safe_copytree(src: str, dst: str, ignore=None):
4546
("xdg-data", f"{home}/.local/share"),
4647
]
4748

49+
# The ~/Desktop folder definition
50+
desktop_dir = Path(GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP))
51+
4852
class Save:
4953
def __init__(self):
5054

@@ -71,24 +75,27 @@ def __init__(self):
7175
safe_copytree(f"{home}/.local/share/backgrounds", "backgrounds")
7276
safe_copytree(f"{home}/.local/share/wallpapers", "xdg-data/wallpapers")
7377
if settings["save-icons"]:
74-
safe_copytree(f"{home}/.icons", ".icons")
75-
safe_copytree(f"{home}/.local/share/icons", "icons")
78+
xdg_path = f"{home}/.local/share"
79+
legacy_path = f"{home}"
80+
if os.path.isdir(f"{xdg_path}/icons") and os.listdir(f"{xdg_path}/icons"):
81+
subprocess.run(["tar", "-czf", "icon-themes.tgz", "-C", xdg_path, "icons"])
82+
if os.path.isdir(f"{legacy_path}/.icons") and os.listdir(f"{legacy_path}/.icons"):
83+
subprocess.run(["tar", "-czf", "icon-themes-legacy.tgz", "-C", legacy_path, ".icons"])
84+
print("[OK] Saving icons")
7685

7786
# Desktop folder
7887
if settings["save-desktop-folder"]:
79-
desktop_dir = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP)
80-
if desktop_dir:
81-
safe_copytree(desktop_dir, "Desktop")
88+
subprocess.run(["tar", "-czf", "desktop-folder.tgz", "-C", str(desktop_dir.parent), str(desktop_dir.name)])
8289
safe_copytree(f"{home}/.local/share/gvfs-metadata", "gvfs-metadata")
90+
print("[OK] Saving ~/Desktop folder")
8391

8492
# Flatpak apps and their data
8593
if flatpak:
8694
if settings["save-installed-flatpaks"]:
87-
print("saving list of installed Flatpak apps")
8895
os.system("ls /var/lib/flatpak/app/ | awk '{print \"flatpak install --system \" $1 \" -y\"}' > ./installed_flatpaks.sh")
8996
os.system("ls ~/.local/share/flatpak/app | awk '{print \"flatpak install --user \" $1 \" -y\"}' > ./installed_user_flatpaks.sh")
97+
print("[OK] Saving list of installed Flatpak apps")
9098
if settings["save-flatpak-data"]:
91-
print("saving user data of installed Flatpak apps")
9299
self.save_flatpak_data()
93100

94101
# Environment specific
@@ -116,24 +123,15 @@ def save_flatpak_data(self):
116123
gsettings = settings["disabled-flatpak-apps-data"]
117124
black_list = gsettings # convert GSettings property to a list
118125

119-
os.makedirs(f"{CACHE}/workspace/app", exist_ok=True)
120-
destdir = f"{CACHE}/workspace/app"
121-
122-
# copy Flatpak apps data
123-
for item in os.listdir(f"{home}/.var/app"):
124-
if item not in black_list and item != "cache":
125-
source_path = os.path.join(f"{home}/.var/app", item)
126-
destination_path = os.path.join(destdir, item)
127-
if os.path.isdir(source_path):
128-
try:
129-
shutil.copytree(source_path, destination_path, ignore=shutil.ignore_patterns('cache'))
130-
except Exception as e:
131-
print(f"Error copying directory {source_path}: {e}")
132-
else:
133-
try:
134-
shutil.copy2(source_path, destination_path)
135-
except Exception as e:
136-
print(f"Error copying file {source_path}: {e}")
126+
cmd = ["tar", "-czf", "flatpak-apps-data.tgz", "--exclude=*/cache"]
127+
128+
for apps in black_list:
129+
cmd.append(f"--exclude={apps}")
130+
131+
cmd.extend(["-C", f"{home}/.var", "app"])
132+
133+
subprocess.run(cmd)
134+
print("[OK] Saving Flatpak apps' data")
137135

138136
class Import:
139137
def __init__(self):
@@ -156,12 +154,11 @@ def __init__(self):
156154
safe_copytree("gnome-shell", f"{home}/.local/share/gnome-shell")
157155
safe_copytree("cinnamon", f"{home}/.local/share/cinnamon")
158156
safe_copytree("plasma", f"{home}/.local/share/plasma")
159-
safe_copytree("Desktop", GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP))
160157
safe_copytree("gvfs-metadata", f"{home}/.local/share/gvfs-metadata")
161158
safe_copytree("backgrounds", f"{home}/.local/share/backgrounds")
162159
safe_copytree("wallpapers", f"{home}/.local/share/wallpapers")
163-
safe_copytree("icons", f"{home}/.local/share/icons")
164-
safe_copytree(".icons", f"{home}/.icons")
160+
self.import_desktop_folder()
161+
self.import_icons()
165162

166163
# Environment specific
167164
if environment:
@@ -177,9 +174,29 @@ def __init__(self):
177174
print(f"[WARN] Unknown DE: {environment_key}")
178175

179176
if flatpak:
180-
if any(os.path.exists(path) for path in ["app", "installed_flatpaks.sh", "installed_user_flatpaks.sh"]):
177+
if any(os.path.exists(path) for path in ["app", "flatpak-apps-data.tgz", "installed_flatpaks.sh", "installed_user_flatpaks.sh"]):
181178
self.create_flatpak_autostart()
182179

180+
# Extract an archive with the Desktop folder
181+
def import_desktop_folder(self):
182+
if os.path.exists("desktop-folder.tgz"):
183+
subprocess.run(["tar", "-xzvf", "desktop-folder.tgz", "-C", str(desktop_dir.parent)])
184+
print("[OK] Extracting a Desktop archive")
185+
else:
186+
safe_copytree("Desktop", GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP))
187+
188+
# Extract an archive with icon themes
189+
def import_icons(self):
190+
if os.path.exists(f"icon-themes.tgz"):
191+
subprocess.run(["tar", "-xzvf", "icon-themes.tgz", "-C", f"{home}/.local/share/"])
192+
print("[OK] Extracting a XDG icons archive")
193+
if os.path.exists(f"icon-themes-legacy.tgz"):
194+
print(f"[OK] Extracting a legacy icons archive")
195+
subprocess.run(["tar", "-xzvf", "icon-themes-legacy.tgz", "-C", f"{home}/"])
196+
else:
197+
safe_copytree("icons", f"{home}/.local/share/icons")
198+
safe_copytree(".icons", f"{home}/.icons")
199+
183200
# Create an autostart file to install Flatpaks from a list after the next login
184201
def create_flatpak_autostart(self):
185202
os.system(f"cp /app/share/savedesktop/savedesktop/core/flatpaks_installer.py {CACHE}/workspace")

src/core/flatpaks_installer.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,16 @@
2323
dest_dir = None
2424

2525
# If the destination directory variable is not 'None', continue in installing Flatpak apps
26-
if not dest_dir == None:
26+
if dest_dir:
2727
# If the destination directory has a directory with installed Flatpak apps user data, install them
2828
if os.path.exists(f"{dest_dir}/app"):
2929
print("copying the Flatpak apps' user data to the ~/.var/app directory")
3030
os.system(f"cp -au {dest_dir}/app/ ~/.var/")
3131

32+
# If the flatpak-apps-data.tgz archive exists, unpack it to the ~/.var/app directory
33+
if os.path.exists(f"{dest_dir}/flatpak-apps-data.tgz"):
34+
subprocess.run(["tar", "-xzvf", "flatpak-apps-data.tgz", "-C", f"{Path.home()}/.var"])
35+
3236
# If the Bash scripts for installing Flatpak apps to the system exist, install them
3337
if os.path.exists(f"{dest_dir}/installed_flatpaks.sh") or os.path.exists(f"{dest_dir}/installed_user_flatpaks.sh"):
3438
print("installing the Flatpak apps on the system")
@@ -78,4 +82,4 @@
7882
os.remove(autostart_file)
7983

8084
# Remove the cache dir after finishing the operations
81-
shutil.rmtree(f"{CACHE}/workspace")
85+
shutil.rmtree(f"{CACHE_FLATPAK}/workspace")

src/gui/window.py

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,18 @@ def __init__(self, *args, **kwargs):
4949
self.headerbar.pack_end(child=self.menu_button)
5050

5151
# primary layout
52+
self.scrolled = Gtk.ScrolledWindow()
53+
self.scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
54+
self.scrolled.set_vexpand(True)
55+
self.scrolled.set_hexpand(True)
56+
self.toolbarview.set_content(self.scrolled)
57+
5258
self.headapp = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
53-
self.headapp.set_valign(Gtk.Align.CENTER)
54-
self.headapp.set_halign(Gtk.Align.CENTER)
55-
self.toolbarview.set_content(self.headapp)
59+
self.headapp.set_valign(Gtk.Align.FILL)
60+
self.headapp.set_halign(Gtk.Align.FILL)
61+
self.headapp.set_vexpand(True)
62+
self.headapp.set_hexpand(True)
63+
self.scrolled.set_child(self.headapp)
5664

5765
# A view container for the menu switcher
5866
self.stack = Adw.ViewStack(vexpand=True)
@@ -512,7 +520,7 @@ def _checkDialog_closed(self, w, response):
512520

513521
# Save configuration
514522
def save_config(self):
515-
print("Saving the configuration is in progress…\nFull output will be available after finishing this operation.")
523+
print("Saving the configuration is in progress…")
516524
self.archive_mode = "--create"
517525
self.archive_name = f"{self.folder}/{self.filename_text}"
518526

@@ -535,15 +543,15 @@ def _set_status_desc_save(self):
535543

536544
# Import configuration
537545
def import_config(self):
538-
print("Importing the configuration is in progress…\nFull output will be available after finishing this operation.")
546+
print("Importing the configuration is in progress…")
539547
self.toast_overlay.dismiss_all()
540548

541549
self.archive_name = self.path_to_import
542550
self.archive_mode = "--unpack"
543551
self.status_title = _("<big><b>Importing configuration …</b></big>\nImporting configuration from:\n<i>{}</i>\n").split('</b>')[0].split('<b>')[-1]
544552
self.status_desc = _("<big><b>Importing configuration …</b></big>\nImporting configuration from:\n<i>{}</i>\n").format(self.archive_name)
545553
self.done_title = _("The configuration has been applied!")
546-
self.done_desc = _("<big><b>{}</b></big>\nYou can log out of the system for the changes to take effect, or go back to the previous page and log out later.\n").format(_("The configuration has been applied!"))
554+
self.done_desc = _("<big><b>{}</b></big>\nYou can log out of the system for the changes to take effect, or go back to the previous page and log out later.\n\n<i>If your archive contains Flatpak apps, they will start installing after the next login.</i>").format(_("The configuration has been applied!"))
547555

548556
self.please_wait()
549557
import_thread = Thread(target=self._call_archive_command)
@@ -552,7 +560,7 @@ def import_config(self):
552560
def _call_archive_command(self):
553561
self.archive_proc = subprocess.Popen(
554562
[sys.executable, "-m", "savedesktop.core.archive", self.archive_mode, self.archive_name],
555-
stdout=subprocess.PIPE,
563+
stdout=None,
556564
stderr=subprocess.PIPE,
557565
text=True,
558566
env={**os.environ, "PYTHONPATH": f"{app_prefix}"}
@@ -576,10 +584,10 @@ def please_wait(self):
576584

577585
# Create box widget for this page
578586
self.status_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
579-
self.status_box.set_halign(Gtk.Align.CENTER)
580-
self.status_box.set_valign(Gtk.Align.CENTER)
587+
self.status_box.set_vexpand(True)
588+
self.status_box.set_hexpand(True)
581589
self.status_box.set_size_request(350, 100)
582-
self.toolbarview.set_content(self.status_box)
590+
self.scrolled.set_child(self.status_box)
583591

584592
# Set bold title
585593
self.set_title(self.status_title)
@@ -684,7 +692,7 @@ def _back_to_main(self, w):
684692
self.status_box.remove(widget)
685693

686694
def _set_default_widgets_state(self):
687-
self.toolbarview.set_content(self.headapp)
695+
self.scrolled.set_child(self.headapp)
688696
self.headerbar.set_title_widget(self.switcher_title)
689697
self.set_title("Save Desktop")
690698
self.apply_handler = self.break_point.connect("apply", self.__on_break_point_apply)
@@ -741,6 +749,8 @@ def on_close(self, w):
741749
# Remove this folder to cleanup unnecessary content created during saving,
742750
# importing, or syncing the configuration only if these files are not present
743751
def remove_cache(self):
744-
files_to_check = [f"{CACHE}/pb", f"{CACHE}/sync", f"{CACHE}/workspace/flatpaks_installer.py"]
745-
if not any(os.path.exists(path) for path in files_to_check):
746-
shutil.rmtree(f"{CACHE}/workspace")
752+
if os.path.exists(f"{CACHE}/workspace"):
753+
files_to_check = [f"{CACHE}/pb", f"{CACHE}/sync", f"{CACHE}/workspace/flatpaks_installer.py"]
754+
if not any(os.path.exists(path) for path in files_to_check):
755+
shutil.rmtree(f"{CACHE}/workspace")
756+

0 commit comments

Comments
 (0)