From dc6ddc4e85dafc8cfc6a9b8735d2e15d45cf2fd0 Mon Sep 17 00:00:00 2001 From: Bruce Leidl Date: Mon, 19 Sep 2022 09:49:49 -0400 Subject: [PATCH] Handle icon paths to specific image files --- citadel-tool/src/sync/desktop_file.rs | 12 +++++++++ citadel-tool/src/sync/desktop_sync.rs | 19 ++++++++++++- citadel-tool/src/sync/icon_cache.rs | 2 +- citadel-tool/src/sync/icons.rs | 39 +++++++++++++++++++++++++-- citadel-tool/src/sync/mod.rs | 2 +- 5 files changed, 69 insertions(+), 5 deletions(-) diff --git a/citadel-tool/src/sync/desktop_file.rs b/citadel-tool/src/sync/desktop_file.rs index 721aba7..c969afe 100644 --- a/citadel-tool/src/sync/desktop_file.rs +++ b/citadel-tool/src/sync/desktop_file.rs @@ -74,6 +74,10 @@ impl DesktopFile { self.get_key_val("Icon") } + pub fn update_icon(&mut self, value: &str) { + self.update_key_val("Icon", value); + } + fn show_in_gnome(&self) -> bool { if self.key_exists("NotShowIn") && self.key_value_contains("NotShowIn", "GNOME") { return false; @@ -118,6 +122,14 @@ impl DesktopFile { None } + fn update_key_val(&mut self, key: &str, value: &str) { + if let Some(&idx) = self.main_map.get(key) { + if idx < self.lines.len() { + self.lines[idx] = Line::KeyValue(key.to_string(), value.to_string()); + } + } + } + pub fn new(filename: &str) -> DesktopFile { DesktopFile { filename: filename.to_string(), diff --git a/citadel-tool/src/sync/desktop_sync.rs b/citadel-tool/src/sync/desktop_sync.rs index 5f421fb..f63f176 100644 --- a/citadel-tool/src/sync/desktop_sync.rs +++ b/citadel-tool/src/sync/desktop_sync.rs @@ -6,6 +6,7 @@ use std::time::SystemTime; use libcitadel::{Realm, Realms, Result, util}; use crate::sync::parser::DesktopFileParser; use std::fs::DirEntry; +use crate::sync::desktop_file::DesktopFile; use crate::sync::icons::IconSync; /// Synchronize dot-desktop files from active realm to a target directory in Citadel. @@ -161,15 +162,31 @@ impl DesktopFileSync { Ok(()) } + fn sync_item_icon(&self, file: &mut DesktopFile) { + let icon_val = match file.icon() { + Some(icon) => icon.to_string(), + None => return, + }; + if let Some(ref icons) = self.icons { + if let Err(err) = icons.sync_icon(file, &icon_val) { + warn!("Failed to sync desktop file icon '{}': {}", icon_val, err); + } + } + } + fn sync_item(&self, item: &DesktopItem) -> Result<()> { - let dfp = DesktopFileParser::parse_from_path(&item.path, "/usr/libexec/citadel-run ")?; + let mut dfp = DesktopFileParser::parse_from_path(&item.path, "/usr/libexec/citadel-run ")?; if dfp.is_showable() { + self.sync_item_icon(&mut dfp); 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)?; } } + + */ } else { debug!("Ignoring desktop file {} as not showable", dfp.filename()); } diff --git a/citadel-tool/src/sync/icon_cache.rs b/citadel-tool/src/sync/icon_cache.rs index ffcedd5..c21ad85 100644 --- a/citadel-tool/src/sync/icon_cache.rs +++ b/citadel-tool/src/sync/icon_cache.rs @@ -24,7 +24,7 @@ impl IconCache { let hash = Self::icon_name_hash(icon_name) % nbuckets; let mut chain_offset = self.read_offset(hash_offset + 4 + (4 * hash as usize))?; - while chain_offset != u32::max_value() as usize { + while chain_offset != u32::MAX as usize { let name_offset = self.read_offset(chain_offset + 4)?; chain_offset = self.read_offset(chain_offset)?; let name = self.read_string(name_offset)?; diff --git a/citadel-tool/src/sync/icons.rs b/citadel-tool/src/sync/icons.rs index cd8f7de..cfd387c 100644 --- a/citadel-tool/src/sync/icons.rs +++ b/citadel-tool/src/sync/icons.rs @@ -4,6 +4,7 @@ use std::path::{Path, PathBuf}; use libcitadel::{Result, util, Realm}; use std::cell::{RefCell, Cell}; +use crate::sync::desktop_file::DesktopFile; pub struct IconSync { realm_base: PathBuf, @@ -26,7 +27,40 @@ impl IconSync { Ok(IconSync { realm_base, cache, known, known_changed }) } - pub fn sync_icon(&self, icon_name: &str) -> Result<()> { + fn sync_icon_filepath(&self, file: &mut DesktopFile, path: &Path) -> Result<()> { + let icon_path = path.canonicalize() + .map_err(context!("Failed to canonicalize icon path {}", path.display()))?; + + let icon_path = icon_path.strip_prefix("/") + .map_err(context!("Failed to strip initial / from {}", icon_path.display()))?; + + let realm_path = self.realm_base.join(icon_path); + + if !realm_path.is_file() { + bail!("Failed to find icon file {}", realm_path.display()); + } + + let dir = Path::new(Self::CITADEL_ICONS).join("filepaths-icons"); + let target = dir.join(realm_path.file_name() + .expect("Icon has no filename?")); + + util::create_dir(&dir)?; + util::copy_file(&realm_path, &target)?; + util::chmod(&target, 0o644)?; + + let target_str = target.display().to_string(); + file.update_icon(&target_str); + + info!("Copied icon from {} to {}", icon_path.display(), target_str); + + Ok(()) + + } + pub fn sync_icon(&self, file: &mut DesktopFile, icon_name: &str) -> Result<()> { + if icon_name.starts_with("/") { + return self.sync_icon_filepath(file, Path::new(icon_name)); + } + if self.is_known(icon_name) { return Ok(()) } @@ -116,7 +150,8 @@ impl IconSync { let target = Path::new(Self::CITADEL_ICONS).join("hicolor").join(stripped); let parent = target.parent().unwrap(); util::create_dir(parent)?; - util::copy_file(icon_path, target)?; + util::copy_file(icon_path, &target)?; + util::chmod(&target, 0o644)?; Ok(()) } } \ No newline at end of file diff --git a/citadel-tool/src/sync/mod.rs b/citadel-tool/src/sync/mod.rs index 56fb5e0..43dee64 100644 --- a/citadel-tool/src/sync/mod.rs +++ b/citadel-tool/src/sync/mod.rs @@ -34,4 +34,4 @@ fn sync(clear: bool) -> Result<()> { } else { DesktopFileSync::clear_target_files() } -} \ No newline at end of file +}