diff --git a/src/DatetimeManager.py b/src/DatetimeManager.py index 7b89573..285cc9c 100644 --- a/src/DatetimeManager.py +++ b/src/DatetimeManager.py @@ -8,17 +8,41 @@ PLUGIN_RC_FILE_PATH = f"{HOME_PATH}/.config/xfce4/panel/datetime-8.rc" ETC_XDG_DATETIME_PATH = "/etc/xdg/pardus/xfce4/panel/datetime-8.rc" -# Copy the default config file if not exists: -if not os.path.exists(PLUGIN_RC_FILE_PATH): +def defaults_available(): + """Whether the packaged default plugin configuration is present. + + It comes from pardus-xfce-settings, which is not a declared dependency of + this library, so it can legitimately be missing. + """ + return os.path.exists(ETC_XDG_DATETIME_PATH) + + +def _seed_config_file(): + """Copy the packaged defaults into the user's config, if there is anything + to copy. Missing defaults are not an error here: the plugin settings simply + start out empty.""" + if os.path.exists(PLUGIN_RC_FILE_PATH) or not defaults_available(): + return + # Create directories if not exists os.makedirs(PLUGIN_RC_FILE_DIRECTORY, exist_ok=True) shutil.copyfile(ETC_XDG_DATETIME_PATH, PLUGIN_RC_FILE_PATH) -# Read config file -config_file_data = "" -with open(PLUGIN_RC_FILE_PATH, "r") as file: - config_file_data = file.read() + +def _read_config_file(): + try: + with open(PLUGIN_RC_FILE_PATH, "r") as file: + return file.read() + except FileNotFoundError: + return "" + + +# Seed and read the config file. Neither step may raise: this module is +# imported at application start-up, so a failure here takes down the whole UI +# before it is shown. +_seed_config_file() +config_file_data = _read_config_file() def get(key): @@ -63,9 +87,23 @@ def save_file(): def restore_default_settings(): - os.remove(PLUGIN_RC_FILE_PATH) + global config_file_data + + if not defaults_available(): + raise FileNotFoundError( + f"Default datetime plugin configuration not found at " + f"{ETC_XDG_DATETIME_PATH}. Is pardus-xfce-settings installed?" + ) + + # copyfile overwrites, so there is no need to remove the current file + # first - and removing it first would leave the user with nothing if the + # copy went on to fail. shutil.copyfile(ETC_XDG_DATETIME_PATH, PLUGIN_RC_FILE_PATH) + # Drop the stale in-memory copy, otherwise the next save_file() would write + # the pre-restore configuration back out. + config_file_data = _read_config_file() + def set_panel_clock(key, value): subprocess.call( diff --git a/src/PanelManager.py b/src/PanelManager.py index 326211f..f97769e 100644 --- a/src/PanelManager.py +++ b/src/PanelManager.py @@ -1,3 +1,5 @@ +import os +import shutil import subprocess import gi @@ -89,14 +91,59 @@ def set_startup_icon(path): xfce4_panel.set_string(f"{whisker_plugin}/button-icon", path) +DEFAULT_PANEL_DIR = "/etc/xdg/pardus/xfce4/panel" +DEFAULT_PANEL_XML = ( + "/etc/xdg/pardus/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml" +) + + +def defaults_available(): + """Whether the packaged default panel configuration is present. + + These files come from pardus-xfce-settings, which is not a declared + dependency of this library. Restoring without them would delete the user's + configuration and put nothing back. + """ + return os.path.isdir(DEFAULT_PANEL_DIR) and os.path.isfile(DEFAULT_PANEL_XML) + + def restore_default_settings(): + """Replace the user's panel configuration with the packaged defaults. + + Raises FileNotFoundError if the defaults are missing, before touching + anything the user owns. + """ + if not defaults_available(): + raise FileNotFoundError( + "Default panel configuration not found under /etc/xdg/pardus/xfce4. " + "Is pardus-xfce-settings installed?" + ) + + panel_dir = os.path.expanduser("~/.config/xfce4/panel") + xml_path = os.path.expanduser( + "~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml" + ) + + # The current configuration is about to be removed and cannot be + # reconstructed, so keep a copy next to it. + backup_dir = f"{panel_dir}.bak" + if os.path.isdir(panel_dir): + shutil.rmtree(backup_dir, ignore_errors=True) + shutil.copytree(panel_dir, backup_dir, symlinks=True) + if os.path.isfile(xml_path): + shutil.copy2(xml_path, f"{xml_path}.bak") + xfce4_panel.reset_property("/", True) + + # Chained with && so that a failure stops the sequence instead of carrying + # on to the next step; check=True surfaces it to the caller. subprocess.run( - """xfce4-panel --quit; - pkill xfconfd; - rm -rf ~/.config/xfce4/panel/* ~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml; - cp -R /etc/xdg/pardus/xfce4/panel/* ~/.config/xfce4/panel/; - cp /etc/xdg/pardus/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml ~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml; - (xfce4-panel &)""", + "xfce4-panel --quit; " + "pkill xfconfd; " + f'rm -rf "{panel_dir}"/* "{xml_path}" && ' + f'cp -R "{DEFAULT_PANEL_DIR}"/* "{panel_dir}/" && ' + f'cp "{DEFAULT_PANEL_XML}" "{xml_path}" && ' + "(xfce4-panel &)", shell=True, + check=True, )