desktop-link 0.1.0

Create shortcut or link files
Documentation
use crate::{Error, Options, Platform};
use std::ffi::OsStr;
use std::fs::OpenOptions;
use std::io::Write;
use std::os::unix::fs::PermissionsExt;
use std::path::PathBuf;

pub struct Xdg;

impl Platform for Xdg {
    fn create(
        &self,
        Options {
            ref mut at,
            name,
            target,
            arguments,
            icon,
            working_directory,
        }: &mut Options,
    ) -> Result<(), Error> {
        at.as_mut_os_string().push(".desktop");

        let mut file = OpenOptions::new()
            .write(true)
            .truncate(true)
            .create(true)
            .open(&at)?;

        writeln!(
            file,
            concat!(
                "[Desktop Entry]\n",
                "Encoding=UTF-8\n",
                "Version=1.0\n",
                "Type=Application\n",
                "Terminal=false"
            )
        )?;

        if let Some(name) = name {
            writeln!(file, "Name={name}")?;
        }

        if let Some(arguments) = arguments {
            writeln!(file, "Exec={} {arguments}", target.display())?;
        }

        if let Some(working_directory) = working_directory {
            writeln!(file, "Path={}", working_directory.display())?;
        }

        if let Some(icon) = icon {
            writeln!(file, "Icon={}", icon.display())?;
        }

        let mut permissions = std::fs::metadata(&at)?.permissions();

        permissions.set_mode(permissions.mode() | 0o110);

        std::fs::set_permissions(&at, permissions)?;

        Ok(())
    }

    fn get_menu_path(&self, name: &OsStr) -> Result<PathBuf, Error> {
        // https://specifications.freedesktop.org/basedir-spec/latest/

        let mut folder = if let Some(share) = std::env::var_os("XDG_DATA_HOME") {
            Ok(PathBuf::from(share).join("applications"))
        } else if let Some(home) = std::env::var_os("HOME") {
            Ok(PathBuf::from(home).join(".local/share/applications"))
        } else {
            Err(Error::Unsupported)
        }?;

        if folder.is_relative() || !std::fs::exists(&folder)? {
            return Err(Error::Unsupported);
        }

        folder.push(name);

        Ok(folder)
    }
}