From fa3f63b5c771f0d488a443f2ee8a9f1535294519 Mon Sep 17 00:00:00 2001 From: Bruce Leidl Date: Mon, 4 Oct 2021 06:15:29 -0400 Subject: [PATCH] Add realm prefix to .desktop files imported into citadel Change the way citadel-desktop-sync works so that gnome-shell can be aware of applications from several realms at once. Each application id is now placed in a separate namespace by adding a prefix to the desktop filename. --- citadel-tool/src/sync/desktop_file.rs | 11 +++++-- citadel-tool/src/sync/desktop_sync.rs | 39 ++++++++++++++++++------- citadel-tool/src/sync/icons.rs | 13 +++++---- citadel-tool/src/sync/mod.rs | 16 ++++++++-- citadel-tool/src/sync/notes.md | 30 +++++++++++++++++++ systemd/citadel-current-watcher.service | 2 +- systemd/citadel-desktop-watcher.service | 2 +- 7 files changed, 89 insertions(+), 24 deletions(-) create mode 100644 citadel-tool/src/sync/notes.md diff --git a/citadel-tool/src/sync/desktop_file.rs b/citadel-tool/src/sync/desktop_file.rs index 9743bff..721aba7 100644 --- a/citadel-tool/src/sync/desktop_file.rs +++ b/citadel-tool/src/sync/desktop_file.rs @@ -3,7 +3,7 @@ use std::fs::File; use std::path::Path; use std::collections::HashMap; -use libcitadel::Result; +use libcitadel::{Result, Realm}; use std::io; @@ -19,8 +19,13 @@ pub struct DesktopFile { impl DesktopFile { - pub fn write_to_dir>(&self, directory: P) -> Result<()> { - let path = directory.as_ref().join(&self.filename); + pub fn write_to_dir>(&self, directory: P, realm: Option<&Realm>) -> Result<()> { + let path = if let Some(r) = realm { + directory.as_ref().join(format!("realm-{}.{}", r.name(), self.filename)) + } else { + directory.as_ref().join(&self.filename) + }; + let f = File::create(&path) .map_err(context!("failed to open desktop file {:?}", path))?; self.write_to(f) diff --git a/citadel-tool/src/sync/desktop_sync.rs b/citadel-tool/src/sync/desktop_sync.rs index ed916e7..5f421fb 100644 --- a/citadel-tool/src/sync/desktop_sync.rs +++ b/citadel-tool/src/sync/desktop_sync.rs @@ -1,5 +1,5 @@ use std::collections::HashSet; -use std::ffi::{OsStr,OsString}; +use std::ffi::OsStr; use std::path::{Path,PathBuf}; use std::time::SystemTime; @@ -44,6 +44,15 @@ impl DesktopItem { impl DesktopFileSync { pub const CITADEL_APPLICATIONS: &'static str = "/home/citadel/.local/share/applications"; + pub fn sync_active_realms() -> Result<()> { + let realms = Realms::load()?; + for realm in realms.active(true) { + let mut sync = DesktopFileSync::new(realm); + sync.run_sync(false)?; + } + Ok(()) + } + pub fn new_current() -> Option { Realms::load_current_realm() .filter(|r| r.is_active()) @@ -51,7 +60,7 @@ impl DesktopFileSync { } pub fn new(realm: Realm) -> Self { - let icons = match IconSync::new() { + let icons = match IconSync::new(&realm) { Ok(icons) => Some(icons), Err(e) => { warn!("Error creating IconSync: {}", e); @@ -111,11 +120,14 @@ impl DesktopFileSync { fn remove_missing_target_files(&mut self) -> Result<()> { let sources = self.source_filenames(); + let prefix = format!("realm-{}.", self.realm.name()); util::read_directory(Self::CITADEL_APPLICATIONS, |dent| { - if !sources.contains(&dent.file_name()) { - let path = dent.path(); - verbose!("Removing desktop entry that no longer exists: {:?}", path); - util::remove_file(path)?; + if let Some(filename) = dent.file_name().to_str() { + if filename.starts_with(&prefix) && !sources.contains(filename) { + let path = dent.path(); + verbose!("Removing desktop entry that no longer exists: {:?}", path); + util::remove_file(path)?; + } } Ok(()) }) @@ -125,10 +137,15 @@ impl DesktopFileSync { path.metadata().and_then(|meta| meta.modified()).ok() } - fn source_filenames(&self) -> HashSet { + fn item_realm_filename(&self, item: &DesktopItem) -> Option { + item.path.file_name().map(|s| { + format!("realm-{}.{}", self.realm.name(), s.to_string_lossy()) + }) + } + + fn source_filenames(&self) -> HashSet { self.items.iter() - .flat_map(|item| item.path.file_name()) - .map(|s| s.to_os_string()) + .flat_map(|item| self.item_realm_filename(item)) .collect() } @@ -137,7 +154,7 @@ impl DesktopFileSync { let target = Path::new(Self::CITADEL_APPLICATIONS).join(item.filename()); if item.is_newer_than(&target) { if let Err(e) = self.sync_item(item) { - warn!("Error synchronzing desktop file {:?} from realm-{}: {}", item.filename(), self.realm.name(), e); + warn!("Error synchronizing desktop file {:?} from realm-{}: {}", item.filename(), self.realm.name(), e); } } } @@ -147,7 +164,7 @@ impl DesktopFileSync { fn sync_item(&self, item: &DesktopItem) -> Result<()> { let dfp = DesktopFileParser::parse_from_path(&item.path, "/usr/libexec/citadel-run ")?; if dfp.is_showable() { - dfp.write_to_dir(Self::CITADEL_APPLICATIONS)?; + dfp.write_to_dir(Self::CITADEL_APPLICATIONS, Some(&self.realm))?; if let Some(icon_name)= dfp.icon() { if let Some(ref icons) = self.icons { icons.sync_icon(icon_name)?; diff --git a/citadel-tool/src/sync/icons.rs b/citadel-tool/src/sync/icons.rs index 51c79f1..cd8f7de 100644 --- a/citadel-tool/src/sync/icons.rs +++ b/citadel-tool/src/sync/icons.rs @@ -1,11 +1,12 @@ use crate::sync::icon_cache::IconCache; use std::collections::HashSet; -use std::path::Path; +use std::path::{Path, PathBuf}; -use libcitadel::{Result, Realms, util}; +use libcitadel::{Result, util, Realm}; use std::cell::{RefCell, Cell}; pub struct IconSync { + realm_base: PathBuf, cache: IconCache, known: RefCell>, known_changed: Cell, @@ -16,12 +17,13 @@ impl IconSync { const KNOWN_ICONS_FILE: &'static str = "/home/citadel/.local/share/icons/known.cache"; const PAPER_ICON_CACHE: &'static str = "/usr/share/icons/Paper/icon-theme.cache"; - pub fn new() -> Result { + pub fn new(realm: &Realm) -> Result { + let realm_base= realm.base_path(); let cache = IconCache::open(Self::PAPER_ICON_CACHE)?; let known = Self::read_known_cache()?; let known = RefCell::new(known); let known_changed = Cell::new(false); - Ok(IconSync { cache, known, known_changed }) + Ok(IconSync { realm_base, cache, known, known_changed }) } pub fn sync_icon(&self, icon_name: &str) -> Result<()> { @@ -56,6 +58,7 @@ impl IconSync { let mut names: Vec = self.known.borrow().iter().map(|s| s.to_string()).collect(); names.sort_unstable(); let out = names.join("\n") + "\n"; + util::create_dir(Self::CITADEL_ICONS)?; util::write_file(Self::KNOWN_ICONS_FILE, out)?; Ok(()) } @@ -71,7 +74,7 @@ impl IconSync { } fn search(&self, subdir: impl AsRef, icon_name: &str) -> Result { - let base = Realms::current_realm_symlink().join(subdir.as_ref()); + let base = self.realm_base.join(subdir.as_ref()); if !base.exists() { return Ok(false) } diff --git a/citadel-tool/src/sync/mod.rs b/citadel-tool/src/sync/mod.rs index cad25de..56fb5e0 100644 --- a/citadel-tool/src/sync/mod.rs +++ b/citadel-tool/src/sync/mod.rs @@ -8,13 +8,23 @@ mod icon_cache; use self::desktop_sync::DesktopFileSync; +fn has_first_arg(args: &[String], arg: &str) -> bool { + args.len() > 1 && args[1].as_str() == arg +} + pub fn main(args: Vec) { Logger::set_log_level(LogLevel::Debug); - let clear = args.len() > 1 && args[1].as_str() == "--clear"; - if let Err(e) = sync(clear) { - println!("Desktop file sync failed: {}", e); + if has_first_arg(&args, "--all") { + if let Err(e) = DesktopFileSync::sync_active_realms() { + println!("Sync all active realms failed: {}", e); + } + } else { + let clear = has_first_arg(&args, "--clear"); + if let Err(e) = sync(clear) { + println!("Desktop file sync failed: {}", e); + } } } diff --git a/citadel-tool/src/sync/notes.md b/citadel-tool/src/sync/notes.md new file mode 100644 index 0000000..b583b24 --- /dev/null +++ b/citadel-tool/src/sync/notes.md @@ -0,0 +1,30 @@ + +### Old Sync + +#### citadel-current-watcher.path + + [Path] + PathChanged=/run/citadel/realms/current + +#### citadel-current-watcher.service + + [Service] + Type=oneshot + ExecStart=/usr/libexec/citadel-desktop-sync --clear + ExecStart=/usr/bin/systemctl restart citadel-desktop-watcher.path + +#### citadel-desktop-watcher.path + + [Path] + PathChanged=/run/citadel/realms/current/current.realm/rootfs/usr/share/applications + PathChanged=/run/citadel/realms/current/current.realm/home/.local/share/applications + +#### citadel-desktop-watcher.service + + [Service] + Type=oneshot + ExecStart=/usr/libexec/citadel-desktop-sync + +### New Sync + +* Added a new command line option `--all` for syncronizing all active realms diff --git a/systemd/citadel-current-watcher.service b/systemd/citadel-current-watcher.service index 270ff2d..f936029 100644 --- a/systemd/citadel-current-watcher.service +++ b/systemd/citadel-current-watcher.service @@ -4,5 +4,5 @@ StartLimitIntervalSec=0 [Service] Type=oneshot -ExecStart=/usr/libexec/citadel-desktop-sync --clear +ExecStart=/usr/libexec/citadel-desktop-sync --all ExecStart=/usr/bin/systemctl restart citadel-desktop-watcher.path diff --git a/systemd/citadel-desktop-watcher.service b/systemd/citadel-desktop-watcher.service index 7f04ab7..b5771d2 100644 --- a/systemd/citadel-desktop-watcher.service +++ b/systemd/citadel-desktop-watcher.service @@ -4,4 +4,4 @@ StartLimitIntervalSec=0 [Service] Type=oneshot -ExecStart=/usr/libexec/citadel-desktop-sync +ExecStart=/usr/libexec/citadel-desktop-sync --all