1use anyhow::{Context, Result};
2use serde::{Deserialize, Serialize};
3use std::env;
4use std::path::PathBuf;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(rename_all = "kebab-case")]
8pub enum InstallScope {
9 User,
10 System,
11}
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct InstallTargets {
15 pub scope: InstallScope,
16 pub app_id: String,
17 pub command_name: String,
18 pub app_dir: PathBuf,
19 pub command_path: PathBuf,
20 pub desktop_path: PathBuf,
21 pub icon_dir: PathBuf,
22 pub state_path: PathBuf,
23}
24
25pub fn home_dir() -> Result<PathBuf> {
26 env::var_os("HOME")
27 .map(PathBuf::from)
28 .context("HOME is not set; cannot resolve user install directories")
29}
30
31fn xdg_data_home() -> Result<PathBuf> {
32 Ok(env::var_os("XDG_DATA_HOME")
33 .map(PathBuf::from)
34 .unwrap_or(home_dir()?.join(".local/share")))
35}
36
37fn xdg_state_home() -> Result<PathBuf> {
38 Ok(env::var_os("XDG_STATE_HOME")
39 .map(PathBuf::from)
40 .unwrap_or(home_dir()?.join(".local/state")))
41}
42
43pub fn targets(scope: InstallScope, app_id: &str, command_name: &str) -> Result<InstallTargets> {
44 let cleaned_id = crate::recipe::sanitize_id(app_id);
45 let cleaned_cmd = crate::recipe::sanitize_command(command_name);
46
47 let t = match scope {
48 InstallScope::User => {
49 let data = xdg_data_home()?;
50 let state = xdg_state_home()?;
51 InstallTargets {
52 scope,
53 app_id: cleaned_id.clone(),
54 command_name: cleaned_cmd.clone(),
55 app_dir: data.join("tarapp/apps").join(&cleaned_id),
56 command_path: home_dir()?.join(".local/bin").join(&cleaned_cmd),
57 desktop_path: data.join("applications").join(format!("{}.desktop", cleaned_id)),
58 icon_dir: data.join("icons/hicolor/256x256/apps"),
59 state_path: state.join("tarapp/apps.json"),
60 }
61 }
62 InstallScope::System => InstallTargets {
63 scope,
64 app_id: cleaned_id.clone(),
65 command_name: cleaned_cmd.clone(),
66 app_dir: PathBuf::from("/opt").join(&cleaned_id),
67 command_path: PathBuf::from("/usr/local/bin").join(&cleaned_cmd),
68 desktop_path: PathBuf::from("/usr/share/applications").join(format!("{}.desktop", cleaned_id)),
69 icon_dir: PathBuf::from("/usr/share/icons/hicolor/256x256/apps"),
70 state_path: PathBuf::from("/var/lib/tarapp/apps.json"),
71 },
72 };
73
74 Ok(t)
75}