release_hub/
utils.rs

1// Copyright (c) 2025 BibCiTeX Contributors
2// SPDX-License-Identifier: MIT OR Apache-2.0
3//
4// This file contains code derived from tauri-plugin-updater
5// Original source: https://github.com/tauri-apps/plugins-workspace/tree/v2/plugins/updater
6// Copyright (c) 2015 - Present - The Tauri Programme within The Commons Conservancy.
7// Licensed under MIT OR MIT/Apache-2.0
8
9//! Platform and system utilities used by the updater.
10//!
11//! Provides small types to model the current OS/architecture and helpers to
12//! derive installation paths.
13
14use crate::{Error, Result};
15use std::path::{Path, PathBuf};
16
17/// Supported operating systems.
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub enum OS {
20    Macos,
21    Windows,
22}
23
24impl std::fmt::Display for OS {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        match self {
27            OS::Macos => write!(f, "macos"),
28            OS::Windows => write!(f, "windows"),
29        }
30    }
31}
32
33/// Supported CPU architectures.
34#[derive(Debug, Clone, PartialEq, Eq)]
35pub enum Arch {
36    X86_64,
37    Arm64,
38}
39
40impl std::fmt::Display for Arch {
41    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42        match self {
43            Arch::X86_64 => write!(f, "x86_64"),
44            Arch::Arm64 => write!(f, "arm64"),
45        }
46    }
47}
48
49/// Detected local system information.
50#[derive(Debug, Clone, PartialEq, Eq)]
51pub struct SystemInfo {
52    pub os: OS,
53    pub arch: Arch,
54}
55
56impl SystemInfo {
57    /// Get local system info.
58    pub fn current() -> Result<Self> {
59        let os = if cfg!(target_os = "macos") {
60            OS::Macos
61        } else if cfg!(target_os = "windows") {
62            OS::Windows
63        } else {
64            return Err(Error::UnsupportedOs);
65        };
66        let arch = if cfg!(target_arch = "x86_64") {
67            Arch::X86_64
68        } else if cfg!(target_arch = "aarch64") {
69            Arch::Arm64
70        } else {
71            return Err(Error::UnsupportedArch);
72        };
73        Ok(Self { os, arch })
74    }
75}
76
77/// Bundle types supported by the installer logic.
78#[derive(Debug, Clone, PartialEq, Eq)]
79pub enum BundleType {
80    MacOSAppZip,
81    MacOSDMG,
82    WindowsMSI,
83    WindowsSetUp,
84}
85
86/// Derive the target extract/installation path from the current executable path.
87///
88/// On macOS, this transforms `/Applications/App.app/Contents/MacOS/App`
89/// into `/Applications/App.app`.
90pub fn extract_path_from_executable(executable_path: &Path) -> Result<PathBuf> {
91    // Return the path of the current executable by default
92    // Example C:\Program Files\My App\
93    let extract_path = executable_path
94        .parent()
95        .map(PathBuf::from)
96        .ok_or(Error::FailedToDetermineExtractPath)?;
97
98    // MacOS example binary is in /Applications/TestApp.app/Contents/MacOS/myApp
99    // We need to get /Applications/<app>.app
100    // TODO(lemarier): Need a better way here
101    // Maybe we could search for <*.app> to get the right path
102    #[cfg(target_os = "macos")]
103    if extract_path
104        .display()
105        .to_string()
106        .contains("Contents/MacOS")
107    {
108        use std::path::PathBuf;
109
110        return extract_path
111            .parent()
112            .map(PathBuf::from)
113            .ok_or(Error::FailedToDetermineExtractPath)?
114            .parent()
115            .map(PathBuf::from)
116            .ok_or(Error::FailedToDetermineExtractPath);
117    }
118
119    Ok(extract_path)
120}