hyprshell_core_lib/util/
exec.rs

1#[derive(Debug, Clone)]
2pub enum ExecType {
3    Flatpak(Box<str>, Box<str>),
4    PWA(Box<str>, Box<str>),
5    FlatpakPWA(Box<str>, Box<str>),
6    Absolute(Box<str>, Box<str>),
7    AppImage(Box<str>, Box<str>),
8    Relative(Box<str>),
9}
10
11const UNKNOWN_EXEC: &str = "unknown";
12
13#[must_use]
14pub fn analyse_exec(exec: &str) -> ExecType {
15    let exec_trim = exec.replace(['\'', '"'], "");
16    // pwa detection
17    if exec.contains("--app-id=") && exec.contains("--profile-directory=") {
18        // "flatpak 'run'" = pwa from browser inside flatpak
19        if exec.contains("flatpak run") || exec.contains("flatpak 'run'") {
20            let browser_exec_in_flatpak = exec_trim
21                .split_whitespace()
22                .find(|s| s.contains("--command="))
23                .and_then(|s| {
24                    s.split('=')
25                        .next_back()
26                        .and_then(|s| s.split('/').next_back())
27                })
28                .unwrap_or(UNKNOWN_EXEC);
29            let flatpak_identifier = exec_trim
30                .split_whitespace()
31                .skip(2)
32                .find(|arg| !arg.starts_with("--"))
33                .unwrap_or(UNKNOWN_EXEC);
34            ExecType::FlatpakPWA(
35                Box::from(flatpak_identifier),
36                Box::from(browser_exec_in_flatpak),
37            )
38        } else {
39            // normal PWA
40            let browser_exec = exec
41                .split_whitespace()
42                .next()
43                .and_then(|s| s.split('/').next_back())
44                .unwrap_or(UNKNOWN_EXEC);
45            let browser_full_exec = exec.split_whitespace().next().unwrap_or(UNKNOWN_EXEC);
46            ExecType::PWA(Box::from(browser_exec), Box::from(browser_full_exec))
47        }
48        // flatpak detection
49    } else if exec.contains("flatpak run") || exec.contains("flatpak 'run'") {
50        let command_in_flatpak = exec_trim
51            .split_whitespace()
52            .find(|s| s.contains("--command="))
53            .and_then(|s| {
54                s.split('=')
55                    .next_back()
56                    .and_then(|s| s.split('/').next_back())
57            })
58            .unwrap_or(UNKNOWN_EXEC);
59        let flatpak_identifier = exec_trim
60            .split_whitespace()
61            .skip(2)
62            .find(|arg| !arg.starts_with("--"))
63            .unwrap_or(UNKNOWN_EXEC);
64        ExecType::Flatpak(Box::from(flatpak_identifier), Box::from(command_in_flatpak))
65    } else if exec_trim.contains(".AppImage") {
66        // AppImage detection
67        let appimage_name = exec_trim
68            .split_whitespace()
69            .next()
70            .and_then(|s| s.split('/').next_back())
71            .and_then(|s| s.split('_').next())
72            .unwrap_or(UNKNOWN_EXEC);
73        ExecType::AppImage(Box::from(appimage_name), Box::from(exec))
74    } else if exec_trim.starts_with('/') {
75        let exec_name = exec_trim
76            .split_whitespace()
77            .next()
78            .and_then(|s| s.split('/').next_back())
79            .unwrap_or(UNKNOWN_EXEC);
80        ExecType::Absolute(Box::from(exec_name), Box::from(exec))
81    } else {
82        ExecType::Relative(Box::from(exec_trim))
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    #[test]
91    fn test_relative_exec() {
92        assert!(matches!(
93            analyse_exec("nautilus --new-window"),
94            ExecType::Relative(ref s) if &**s == "nautilus --new-window"
95        ));
96    }
97
98    #[test]
99    fn test_flatpak_pwa_exec() {
100        assert!(matches!(
101            analyse_exec(
102                "flatpak 'run' '--command=/app/bin/chromium' 'org.chromium.Chromium' '--profile-directory=Default' '--app-id=awf'"
103            ),
104            ExecType::FlatpakPWA(ref id, ref browser) if &**id == "org.chromium.Chromium" && &**browser == "chromium"
105        ));
106    }
107
108    #[test]
109    fn test_appimage_exec() {
110        assert!(matches!(
111            analyse_exec(
112                "/home/user/Applications/ungoogled-chromium_71.0.3578.98-2_linux_awf.AppImage %u"
113            ),
114            ExecType::AppImage(ref name, ref path) if &**name == "ungoogled-chromium" && &**path == "/home/user/Applications/ungoogled-chromium_71.0.3578.98-2_linux_awf.AppImage %u"
115        ));
116    }
117
118    #[test]
119    fn test_absolute_pwa_exec() {
120        assert!(matches!(
121            analyse_exec(
122                "/opt/google/chrome/google-chrome --profile-directory=Default --app-id=awf"
123            ),
124            ExecType::PWA(ref browser, ref path) if &**browser == "google-chrome" && &**path == "/opt/google/chrome/google-chrome"
125        ));
126    }
127
128    #[test]
129    fn test_flatpak_exec() {
130        assert!(matches!(
131            analyse_exec("flatpak run org.mozilla.firefox"),
132            ExecType::Flatpak(ref id, ref command) if &**id == "org.mozilla.firefox" && &**command == "unknown"
133        ));
134    }
135
136    #[test]
137    fn test_absolute_exec() {
138        assert!(matches!(
139            analyse_exec("/usr/bin/firefox"),
140            ExecType::Absolute(ref name, ref path) if &**name == "firefox" && &**path == "/usr/bin/firefox"
141        ));
142    }
143}