forked from brl/citadel-tools
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.
This commit is contained in:
parent
e07d35944a
commit
fa3f63b5c7
@ -3,7 +3,7 @@ use std::fs::File;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use libcitadel::Result;
|
use libcitadel::{Result, Realm};
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
|
|
||||||
@ -19,8 +19,13 @@ pub struct DesktopFile {
|
|||||||
|
|
||||||
impl DesktopFile {
|
impl DesktopFile {
|
||||||
|
|
||||||
pub fn write_to_dir<P: AsRef<Path>>(&self, directory: P) -> Result<()> {
|
pub fn write_to_dir<P: AsRef<Path>>(&self, directory: P, realm: Option<&Realm>) -> Result<()> {
|
||||||
let path = directory.as_ref().join(&self.filename);
|
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)
|
let f = File::create(&path)
|
||||||
.map_err(context!("failed to open desktop file {:?}", path))?;
|
.map_err(context!("failed to open desktop file {:?}", path))?;
|
||||||
self.write_to(f)
|
self.write_to(f)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::ffi::{OsStr,OsString};
|
use std::ffi::OsStr;
|
||||||
use std::path::{Path,PathBuf};
|
use std::path::{Path,PathBuf};
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
@ -44,6 +44,15 @@ impl DesktopItem {
|
|||||||
impl DesktopFileSync {
|
impl DesktopFileSync {
|
||||||
pub const CITADEL_APPLICATIONS: &'static str = "/home/citadel/.local/share/applications";
|
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<Self> {
|
pub fn new_current() -> Option<Self> {
|
||||||
Realms::load_current_realm()
|
Realms::load_current_realm()
|
||||||
.filter(|r| r.is_active())
|
.filter(|r| r.is_active())
|
||||||
@ -51,7 +60,7 @@ impl DesktopFileSync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(realm: Realm) -> Self {
|
pub fn new(realm: Realm) -> Self {
|
||||||
let icons = match IconSync::new() {
|
let icons = match IconSync::new(&realm) {
|
||||||
Ok(icons) => Some(icons),
|
Ok(icons) => Some(icons),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("Error creating IconSync: {}", e);
|
warn!("Error creating IconSync: {}", e);
|
||||||
@ -111,12 +120,15 @@ impl DesktopFileSync {
|
|||||||
|
|
||||||
fn remove_missing_target_files(&mut self) -> Result<()> {
|
fn remove_missing_target_files(&mut self) -> Result<()> {
|
||||||
let sources = self.source_filenames();
|
let sources = self.source_filenames();
|
||||||
|
let prefix = format!("realm-{}.", self.realm.name());
|
||||||
util::read_directory(Self::CITADEL_APPLICATIONS, |dent| {
|
util::read_directory(Self::CITADEL_APPLICATIONS, |dent| {
|
||||||
if !sources.contains(&dent.file_name()) {
|
if let Some(filename) = dent.file_name().to_str() {
|
||||||
|
if filename.starts_with(&prefix) && !sources.contains(filename) {
|
||||||
let path = dent.path();
|
let path = dent.path();
|
||||||
verbose!("Removing desktop entry that no longer exists: {:?}", path);
|
verbose!("Removing desktop entry that no longer exists: {:?}", path);
|
||||||
util::remove_file(path)?;
|
util::remove_file(path)?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -125,10 +137,15 @@ impl DesktopFileSync {
|
|||||||
path.metadata().and_then(|meta| meta.modified()).ok()
|
path.metadata().and_then(|meta| meta.modified()).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn source_filenames(&self) -> HashSet<OsString> {
|
fn item_realm_filename(&self, item: &DesktopItem) -> Option<String> {
|
||||||
|
item.path.file_name().map(|s| {
|
||||||
|
format!("realm-{}.{}", self.realm.name(), s.to_string_lossy())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn source_filenames(&self) -> HashSet<String> {
|
||||||
self.items.iter()
|
self.items.iter()
|
||||||
.flat_map(|item| item.path.file_name())
|
.flat_map(|item| self.item_realm_filename(item))
|
||||||
.map(|s| s.to_os_string())
|
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +154,7 @@ impl DesktopFileSync {
|
|||||||
let target = Path::new(Self::CITADEL_APPLICATIONS).join(item.filename());
|
let target = Path::new(Self::CITADEL_APPLICATIONS).join(item.filename());
|
||||||
if item.is_newer_than(&target) {
|
if item.is_newer_than(&target) {
|
||||||
if let Err(e) = self.sync_item(item) {
|
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<()> {
|
fn sync_item(&self, item: &DesktopItem) -> Result<()> {
|
||||||
let dfp = DesktopFileParser::parse_from_path(&item.path, "/usr/libexec/citadel-run ")?;
|
let dfp = DesktopFileParser::parse_from_path(&item.path, "/usr/libexec/citadel-run ")?;
|
||||||
if dfp.is_showable() {
|
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(icon_name)= dfp.icon() {
|
||||||
if let Some(ref icons) = self.icons {
|
if let Some(ref icons) = self.icons {
|
||||||
icons.sync_icon(icon_name)?;
|
icons.sync_icon(icon_name)?;
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
use crate::sync::icon_cache::IconCache;
|
use crate::sync::icon_cache::IconCache;
|
||||||
use std::collections::HashSet;
|
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};
|
use std::cell::{RefCell, Cell};
|
||||||
|
|
||||||
pub struct IconSync {
|
pub struct IconSync {
|
||||||
|
realm_base: PathBuf,
|
||||||
cache: IconCache,
|
cache: IconCache,
|
||||||
known: RefCell<HashSet<String>>,
|
known: RefCell<HashSet<String>>,
|
||||||
known_changed: Cell<bool>,
|
known_changed: Cell<bool>,
|
||||||
@ -16,12 +17,13 @@ impl IconSync {
|
|||||||
const KNOWN_ICONS_FILE: &'static str = "/home/citadel/.local/share/icons/known.cache";
|
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";
|
const PAPER_ICON_CACHE: &'static str = "/usr/share/icons/Paper/icon-theme.cache";
|
||||||
|
|
||||||
pub fn new() -> Result<Self> {
|
pub fn new(realm: &Realm) -> Result<Self> {
|
||||||
|
let realm_base= realm.base_path();
|
||||||
let cache = IconCache::open(Self::PAPER_ICON_CACHE)?;
|
let cache = IconCache::open(Self::PAPER_ICON_CACHE)?;
|
||||||
let known = Self::read_known_cache()?;
|
let known = Self::read_known_cache()?;
|
||||||
let known = RefCell::new(known);
|
let known = RefCell::new(known);
|
||||||
let known_changed = Cell::new(false);
|
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<()> {
|
pub fn sync_icon(&self, icon_name: &str) -> Result<()> {
|
||||||
@ -56,6 +58,7 @@ impl IconSync {
|
|||||||
let mut names: Vec<String> = self.known.borrow().iter().map(|s| s.to_string()).collect();
|
let mut names: Vec<String> = self.known.borrow().iter().map(|s| s.to_string()).collect();
|
||||||
names.sort_unstable();
|
names.sort_unstable();
|
||||||
let out = names.join("\n") + "\n";
|
let out = names.join("\n") + "\n";
|
||||||
|
util::create_dir(Self::CITADEL_ICONS)?;
|
||||||
util::write_file(Self::KNOWN_ICONS_FILE, out)?;
|
util::write_file(Self::KNOWN_ICONS_FILE, out)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -71,7 +74,7 @@ impl IconSync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search(&self, subdir: impl AsRef<Path>, icon_name: &str) -> Result<bool> {
|
fn search(&self, subdir: impl AsRef<Path>, icon_name: &str) -> Result<bool> {
|
||||||
let base = Realms::current_realm_symlink().join(subdir.as_ref());
|
let base = self.realm_base.join(subdir.as_ref());
|
||||||
if !base.exists() {
|
if !base.exists() {
|
||||||
return Ok(false)
|
return Ok(false)
|
||||||
}
|
}
|
||||||
|
@ -8,14 +8,24 @@ mod icon_cache;
|
|||||||
|
|
||||||
use self::desktop_sync::DesktopFileSync;
|
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<String>) {
|
pub fn main(args: Vec<String>) {
|
||||||
|
|
||||||
Logger::set_log_level(LogLevel::Debug);
|
Logger::set_log_level(LogLevel::Debug);
|
||||||
let clear = args.len() > 1 && args[1].as_str() == "--clear";
|
|
||||||
|
|
||||||
|
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) {
|
if let Err(e) = sync(clear) {
|
||||||
println!("Desktop file sync failed: {}", e);
|
println!("Desktop file sync failed: {}", e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sync(clear: bool) -> Result<()> {
|
fn sync(clear: bool) -> Result<()> {
|
||||||
|
30
citadel-tool/src/sync/notes.md
Normal file
30
citadel-tool/src/sync/notes.md
Normal file
@ -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
|
@ -4,5 +4,5 @@ StartLimitIntervalSec=0
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
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
|
ExecStart=/usr/bin/systemctl restart citadel-desktop-watcher.path
|
||||||
|
@ -4,4 +4,4 @@ StartLimitIntervalSec=0
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
ExecStart=/usr/libexec/citadel-desktop-sync
|
ExecStart=/usr/libexec/citadel-desktop-sync --all
|
||||||
|
Loading…
Reference in New Issue
Block a user