fixes
This commit is contained in:
@@ -10,6 +10,10 @@ paths = [
|
||||
source = 'payload\sample_app.cmd'
|
||||
destination = '{LocalAppData}\CovenantSetupSample\bin\sample_app.cmd'
|
||||
|
||||
[[files]]
|
||||
source = 'payload\post_install.ps1'
|
||||
destination = '{LocalAppData}\CovenantSetupSample\post_install.ps1'
|
||||
|
||||
[[registry]]
|
||||
key = 'HKCU\Software\CovenantSetupSample'
|
||||
name = 'InstallRoot'
|
||||
@@ -20,13 +24,17 @@ path = '{Desktop}\CovenantSetupSample.lnk'
|
||||
target = '{LocalAppData}\CovenantSetupSample\bin\sample_app.cmd'
|
||||
description = 'Launch the Covenant-Setup sample payload'
|
||||
|
||||
# The post-install script is copied into the install root above, so it is
|
||||
# invoked by name with the working directory already pointing there. This keeps
|
||||
# the script locatable for both direct and packaged (temp-extracted) installs,
|
||||
# where the manifest's own directory is not the process working directory.
|
||||
[[scripts]]
|
||||
command = 'powershell'
|
||||
args = [
|
||||
'-ExecutionPolicy',
|
||||
'Bypass',
|
||||
'-File',
|
||||
'payload\post_install.ps1'
|
||||
'post_install.ps1'
|
||||
]
|
||||
working_directory = '{LocalAppData}\CovenantSetupSample'
|
||||
|
||||
|
||||
+8
-4
@@ -35,8 +35,12 @@ cargo run -- uninstall examples/journal.json --json
|
||||
|
||||
Expected effects:
|
||||
|
||||
- Creates `%LOCALAPPDATA%\CovenantSetupExample`
|
||||
- Copies `sample_app.cmd` into the `bin` directory
|
||||
- Writes `HKCU\Software\CovenantSetupExample\InstallRoot`
|
||||
- Creates `%LOCALAPPDATA%\CovenantSetupSample`
|
||||
- Copies `sample_app.cmd` into the `bin` directory and `post_install.ps1` into the install root
|
||||
- Writes `HKCU\Software\CovenantSetupSample\InstallRoot`
|
||||
- Creates a desktop shortcut
|
||||
- Runs an inline PowerShell post-install command and records only the script execution in the journal
|
||||
- Runs `post_install.ps1` from the install root, which writes a timestamped marker under `logs\`
|
||||
|
||||
Every directory, file, registry value, shortcut, and script execution is recorded in the
|
||||
journal, so uninstall reverses all of them (and the `purge` spec removes the whole install
|
||||
root, including the `logs\` directory the script created).
|
||||
|
||||
+2
-2
@@ -82,7 +82,7 @@ pub(crate) fn build_packaged_installer(
|
||||
manifest: &InstallManifest,
|
||||
logger: &Logger,
|
||||
) -> Result<(), AppError> {
|
||||
fs::copy(current_exe, &exe_target)?;
|
||||
fs::copy(current_exe, exe_target)?;
|
||||
let bundled_manifest_name = expected_manifest_file_name(&manifest.app_name);
|
||||
let bundle = EmbeddedBundle {
|
||||
metadata: PackagedApp {
|
||||
@@ -643,7 +643,7 @@ mod tests {
|
||||
temp.path(),
|
||||
&manifest,
|
||||
&bundled_manifest_name,
|
||||
&[generated_installer.clone()],
|
||||
std::slice::from_ref(&generated_installer),
|
||||
)
|
||||
.unwrap();
|
||||
files.sort_by(|left, right| left.relative_path.cmp(&right.relative_path));
|
||||
|
||||
+3
-3
@@ -14,6 +14,7 @@ pub(crate) struct InstallRuntime {
|
||||
pub(crate) uninstall_registry_root: RegistryRoot,
|
||||
pub(crate) uninstall_registry_key: String,
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn install(
|
||||
manifest_path: &Path,
|
||||
journal_path: Option<PathBuf>,
|
||||
@@ -285,8 +286,8 @@ pub(crate) fn install(
|
||||
);
|
||||
let cancelled = matches!(err, AppError::Cancelled);
|
||||
let mut rollback_error_msg = None;
|
||||
if let Some(runtime) = &runtime_opt {
|
||||
if !journal.actions.is_empty() {
|
||||
if let Some(runtime) = &runtime_opt
|
||||
&& !journal.actions.is_empty() {
|
||||
let write_res = (|| -> Result<(), AppError> {
|
||||
write_journal(&runtime.journal_path, &journal)?;
|
||||
let read_back = fs::read_to_string(&runtime.journal_path)?;
|
||||
@@ -328,7 +329,6 @@ pub(crate) fn install(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if cancelled && rollback_error_msg.is_none() {
|
||||
let _ = finish_gui_progress(
|
||||
|
||||
@@ -58,6 +58,7 @@ pub(crate) fn start_tui_progress(ui_mode: UiMode, label: String) -> Option<TuiPr
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn start_gui_progress(
|
||||
ui_mode: UiMode,
|
||||
sys: &dyn Sys,
|
||||
|
||||
@@ -20,6 +20,7 @@ pub(crate) trait Sys: Send + Sync {
|
||||
fn prompt_reboot_tui(&self) -> Result<bool, AppError>;
|
||||
|
||||
// (3) cleanup helper self-delete
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn spawn_cleanup_helper(
|
||||
&self,
|
||||
target_exe: &Path,
|
||||
|
||||
+10
-5
@@ -6,6 +6,7 @@ use std::os::windows::process::CommandExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn uninstall(
|
||||
journal_path: &Path,
|
||||
elevate: bool,
|
||||
@@ -267,10 +268,11 @@ pub(crate) fn cleanup(
|
||||
sys.remove_file_with_fallback(&target_exe, &effective_logger)?;
|
||||
reboot_required = target_exe.exists();
|
||||
}
|
||||
if let Some(install_root) = install_root {
|
||||
if install_root.exists() && fs::read_dir(&install_root)?.next().is_none() {
|
||||
win::remove_directory_if_exists(&install_root, &effective_logger)?;
|
||||
}
|
||||
if let Some(install_root) = install_root
|
||||
&& install_root.exists()
|
||||
&& fs::read_dir(&install_root)?.next().is_none()
|
||||
{
|
||||
win::remove_directory_if_exists(&install_root, &effective_logger)?;
|
||||
}
|
||||
reboot_required |= sys.schedule_helper_self_cleanup(&effective_logger)?;
|
||||
if ui_mode == UiMode::Gui && !automation {
|
||||
@@ -383,7 +385,10 @@ pub(crate) fn journal_requires_admin(
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
JournalAction::WriteRegistry { root, .. } if matches!(root, RegistryRoot::Hklm) => {
|
||||
JournalAction::WriteRegistry {
|
||||
root: RegistryRoot::Hklm,
|
||||
..
|
||||
} => {
|
||||
return Ok(true);
|
||||
}
|
||||
_ => {}
|
||||
|
||||
+8
-8
@@ -4,18 +4,18 @@ pub fn create_directory_recursive(path: &Path, logger: &Logger) -> Result<(), Ap
|
||||
if path.as_os_str().is_empty() || path.exists() {
|
||||
return Ok(());
|
||||
}
|
||||
if let Some(parent) = path.parent() {
|
||||
if parent != path {
|
||||
create_directory_recursive(parent, logger)?;
|
||||
}
|
||||
if let Some(parent) = path.parent()
|
||||
&& parent != path
|
||||
{
|
||||
create_directory_recursive(parent, logger)?;
|
||||
}
|
||||
logger.unsafe_enter("CreateDirectoryW", json!({"path": path}));
|
||||
let result = unsafe { CreateDirectoryW(PCWSTR(Utf16Arg::from_path(path).as_ptr()), None) };
|
||||
logger.unsafe_exit("CreateDirectoryW", json!({"ok": result.is_ok()}));
|
||||
if let Err(err) = result {
|
||||
if !path.exists() {
|
||||
return Err(err.into());
|
||||
}
|
||||
if let Err(err) = result
|
||||
&& !path.exists()
|
||||
{
|
||||
return Err(err.into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user