Skip to main content

zng_ext_setup/task/
copy_current_exe.rs

1use std::path::PathBuf;
2
3use crate::task::{SetupTask, SetupTaskError};
4
5/// Setup task that copies [`std::env::current_exe`] to a location.
6///
7/// The current exe is the setup executable, this task is useful when the setup executable
8/// is also the app executable, or when it is needed to uninstall.
9pub enum CopyCurrentExe {}
10impl SetupTask for CopyCurrentExe {
11    type InstallConfig = CopyCurrentExeConfig;
12
13    type PrepareInstall = PrepareInstallData;
14
15    type Install = InstallData;
16
17    fn task_type_id() -> super::TaskTypeId {
18        "zng-setup/CopyCurrentExe".into()
19    }
20
21    async fn prepare_install(args: super::PrepareInstallArgs<Self>) -> Result<Self::PrepareInstall, SetupTaskError> {
22        let exe = match std::env::current_exe() {
23            Ok(p) => p,
24            Err(e) => return Err(SetupTaskError::io(PathBuf::new(), e)),
25        };
26        let temp_exe = args.config.destination_exe.with_added_extension(".cce-tmp");
27
28        let target_dir = temp_exe.parent().unwrap();
29        if let Err(e) = zng_task::fs::create_dir_all(target_dir).await {
30            return Err(SetupTaskError::io(target_dir.to_path_buf(), e));
31        }
32
33        if let Err(e) = zng_task::fs::copy(&exe, &temp_exe).await {
34            return Err(SetupTaskError::io(temp_exe, e));
35        }
36
37        Ok(PrepareInstallData {
38            temp_exe,
39            destination_exe: args.config.destination_exe,
40        })
41    }
42
43    async fn install(args: super::InstallArgs<Self>) -> Result<Self::Install, super::InstallTaskError<Self::Install>> {
44        if let Err(e) = zng_task::fs::rename(&args.data.temp_exe, &args.data.destination_exe).await {
45            let _ = zng_task::fs::remove_file(&args.data.temp_exe).await;
46            return Err(super::InstallTaskError {
47                error: SetupTaskError::io(args.data.temp_exe, e),
48                clean_data: None,
49            });
50        }
51        Ok(InstallData {
52            destination_exe: args.data.destination_exe,
53        })
54    }
55
56    async fn cancel_install(args: super::CancelInstallArgs<Self>) -> Result<(), SetupTaskError> {
57        if let Err(e) = zng_task::fs::remove_file(&args.data.temp_exe).await
58            && !matches!(e.kind(), std::io::ErrorKind::NotFound)
59        {
60            return Err(SetupTaskError::io(args.data.temp_exe, e));
61        }
62        Ok(())
63    }
64
65    async fn validate_uninstall(args: super::ValidateUninstallArgs<Self>) -> Result<Self::Install, SetupTaskError> {
66        Ok(args.data)
67    }
68
69    async fn uninstall(args: super::UninstallArgs<Self>) -> Result<(), SetupTaskError> {
70        if let Err(e) = zng_task::fs::remove_file(&args.data.destination_exe).await
71            && !matches!(e.kind(), std::io::ErrorKind::NotFound)
72        {
73            return Err(SetupTaskError::io(args.data.destination_exe, e));
74        }
75        Ok(())
76    }
77}
78
79/// Config for [`CopyCurrentExe`].
80#[non_exhaustive]
81pub struct CopyCurrentExeConfig {
82    /// Current exe is copied to this path.
83    pub destination_exe: PathBuf,
84}
85impl CopyCurrentExeConfig {
86    /// New with destination path.
87    pub fn new(destination_exe: PathBuf) -> Self {
88        Self { destination_exe }
89    }
90}
91
92#[doc(hidden)]
93#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize)]
94pub struct PrepareInstallData {
95    temp_exe: PathBuf,
96    destination_exe: PathBuf,
97}
98
99#[doc(hidden)]
100#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize)]
101pub struct InstallData {
102    destination_exe: PathBuf,
103}