Skip to content

Commit

Permalink
feat(nsis): add appdata_paths option
Browse files Browse the repository at this point in the history
  • Loading branch information
amr-crabnebula committed Sep 18, 2023
1 parent cd483f1 commit 32d390c
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 14 deletions.
11 changes: 11 additions & 0 deletions crates/config/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,17 @@
"description": "Whether to display a language selector dialog before the installer and uninstaller windows are rendered or not. By default the OS language is selected, with a fallback to the first language in the `languages` array.",
"default": false,
"type": "boolean"
},
"appdataPaths": {
"description": "List of paths where your app stores data. This options tells the uninstaller to provide the user with an option (disabled by default) whether they want to rmeove your app data or keep it.\n\nThe path should use a constant from https://nsis.sourceforge.io/Docs/Chapter4.html#varconstant in addition to `$IDENTIFIER`, `$PUBLISHER` and `$PRODUCTNAME`, for example, if you store your app data in `C:\\\\Users\\\\<user>\\\\AppData\\\\Local\\\\<your-company-name>\\\\<your-product-name>` you'd need to specify ```toml [package.metadata.packager.nsis] appdata-paths = [\"$LOCALAPPDATA/$PUBLISHER/$PRODUCTNAME\"] ```",
"default": null,
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
}
},
"additionalProperties": false
Expand Down
14 changes: 14 additions & 0 deletions crates/config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,20 @@ pub struct NsisConfig {
alias = "display_language_selector"
)]
pub display_language_selector: bool,
/// List of paths where your app stores data.
/// This options tells the uninstaller to provide the user with an option
/// (disabled by default) whether they want to rmeove your app data or keep it.
///
/// The path should use a constant from https://nsis.sourceforge.io/Docs/Chapter4.html#varconstant
/// in addition to `$IDENTIFIER`, `$PUBLISHER` and `$PRODUCTNAME`, for example, if you store your
/// app data in `C:\\Users\\<user>\\AppData\\Local\\<your-company-name>\\<your-product-name>`
/// you'd need to specify
/// ```toml
/// [package.metadata.packager.nsis]
/// appdata-paths = ["$LOCALAPPDATA/$PUBLISHER/$PRODUCTNAME"]
/// ```
#[serde(default, alias = "appdata-paths", alias = "appdata_paths")]
pub appdata_paths: Option<Vec<String>>,
}

/// The Windows configuration.
Expand Down
11 changes: 11 additions & 0 deletions crates/packager/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,17 @@
"description": "Whether to display a language selector dialog before the installer and uninstaller windows are rendered or not. By default the OS language is selected, with a fallback to the first language in the `languages` array.",
"default": false,
"type": "boolean"
},
"appdataPaths": {
"description": "List of paths where your app stores data. This options tells the uninstaller to provide the user with an option (disabled by default) whether they want to rmeove your app data or keep it.\n\nThe path should use a constant from https://nsis.sourceforge.io/Docs/Chapter4.html#varconstant in addition to `$IDENTIFIER`, `$PUBLISHER` and `$PRODUCTNAME`, for example, if you store your app data in `C:\\\\Users\\\\<user>\\\\AppData\\\\Local\\\\<your-company-name>\\\\<your-product-name>` you'd need to specify ```toml [package.metadata.packager.nsis] appdata-paths = [\"$LOCALAPPDATA/$PUBLISHER/$PRODUCTNAME\"] ```",
"default": null,
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
}
},
"additionalProperties": false
Expand Down
17 changes: 10 additions & 7 deletions crates/packager/src/nsis/installer.nsi
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ ${StrLoc}
!define HEADERIMAGE "{{header_image}}"
!define MAINBINARYNAME "{{main_binary_name}}"
!define MAINBINARYSRCPATH "{{main_binary_path}}"
!define BUNDLEID "{{bundle_id}}"
!define IDENTIFIER "{{identifier}}"
!define COPYRIGHT "{{copyright}}"
!define OUTFILE "{{out_file}}"
!define ARCH "{{arch}}"
Expand Down Expand Up @@ -321,6 +321,7 @@ Var AppStartMenuFolder

; Uninstaller Pages
; 1. Confirm uninstall page
{{#if appdata_paths}}
Var DeleteAppDataCheckbox
Var DeleteAppDataCheckboxState
!define /ifndef WS_EX_LAYOUTRTL 0x00400000
Expand All @@ -340,6 +341,7 @@ FunctionEnd
Function un.ConfirmLeave
SendMessage $DeleteAppDataCheckbox ${BM_GETCHECK} 0 0 $DeleteAppDataCheckboxState
FunctionEnd
{{/if}}
!insertmacro MUI_UNPAGE_CONFIRM

; 2. Uninstalling Page
Expand Down Expand Up @@ -617,13 +619,14 @@ Section Uninstall
DeleteRegValue HKCU "${MANUPRODUCTKEY}" "Installer Language"

; Delete app data
{{#if appdata_paths}}
${If} $DeleteAppDataCheckboxState == 1
!if "${BUNDLEID}" != ""
SetShellVarContext current
RmDir /r "$APPDATA\${BUNDLEID}"
RmDir /r "$LOCALAPPDATA\${BUNDLEID}"
!endif
{{#each appdata_paths}}
RmDir /r "{{unescape_dollar_sign this}}"
{{/each}}
${EndIf}
{{/if}}

${GetOptions} $CMDLINE "/P" $R0
IfErrors +2 0
Expand All @@ -642,11 +645,11 @@ FunctionEnd

Function CreateDesktopShortcut
CreateShortcut "$DESKTOP\${PRODUCTNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe"
ApplicationID::Set "$DESKTOP\${PRODUCTNAME}.lnk" "${BUNDLEID}"
ApplicationID::Set "$DESKTOP\${PRODUCTNAME}.lnk" "${IDENTIFIER}"
FunctionEnd

Function CreateStartMenuShortcut
CreateDirectory "$SMPROGRAMS\$AppStartMenuFolder"
CreateShortcut "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe"
ApplicationID::Set "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk" "${BUNDLEID}"
ApplicationID::Set "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk" "${IDENTIFIER}"
FunctionEnd
30 changes: 27 additions & 3 deletions crates/packager/src/nsis/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,18 @@ fn unescape_newlines(
Ok(())
}

fn unescape_dollar_sign(
h: &handlebars::Helper<'_, '_>,
_: &Handlebars<'_>,
_: &handlebars::Context,
_: &mut handlebars::RenderContext<'_, '_>,
out: &mut dyn handlebars::Output,
) -> handlebars::HelperResult {
let s = h.param(0).unwrap().render();
out.write(&s.replace("$$", "$"))?;
Ok(())
}

fn add_build_number_if_needed(version_str: &str) -> crate::Result<String> {
let version = semver::Version::parse(version_str)?;
if !version.build.is_empty() {
Expand Down Expand Up @@ -288,12 +300,12 @@ fn build_nsis_app_installer(
data.insert("additional_plugins_path", to_json(dir));
}

let bundle_id = config.identifier();
let identifier = config.identifier();
let manufacturer = config.publisher();

data.insert("arch", to_json(arch));
data.insert("bundle_id", to_json(bundle_id));
data.insert("manufacturer", to_json(manufacturer));
data.insert("identifier", to_json(identifier));
data.insert("manufacturer", to_json(&manufacturer));
data.insert("product_name", to_json(&config.product_name));
data.insert("short_description", to_json(&config.description));
data.insert("copyright", to_json(&config.copyright));
Expand Down Expand Up @@ -369,6 +381,17 @@ fn build_nsis_app_installer(
}),
);
}
if let Some(appdata_paths) = &nsis.appdata_paths {
let appdata_paths = appdata_paths
.iter()
.map(|p| {
p.replace("$PUBLISHER", &manufacturer)
.replace("$PRODUCTNAME", &config.product_name)
.replace("$IDENTIFIER", config.identifier())
})
.collect::<Vec<_>>();
data.insert("appdata_paths", to_json(appdata_paths));
}
}

data.insert("install_mode", to_json(install_mode));
Expand Down Expand Up @@ -421,6 +444,7 @@ fn build_nsis_app_installer(
handlebars.register_helper("or", Box::new(handlebars_or));
handlebars.register_helper("association-description", Box::new(association_description));
handlebars.register_helper("unescape_newlines", Box::new(unescape_newlines));
handlebars.register_helper("unescape_dollar_sign", Box::new(unescape_dollar_sign));
handlebars.register_escape_fn(|s| {
let mut output = String::new();
for c in s.chars() {
Expand Down
2 changes: 1 addition & 1 deletion crates/packager/src/wix/main.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@
Icon="ProductIcon"
{{/if}}
WorkingDirectory="INSTALLDIR">
<ShortcutProperty Key="System.AppUserModel.ID" Value="{{bundle_id}}"/>
<ShortcutProperty Key="System.AppUserModel.ID" Value="{{identifier}}"/>
</Shortcut>
<RemoveFolder Id="ApplicationProgramsFolder" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\\{{manufacturer}}\\{{product_name}}" Name="Start Menu Shortcut" Type="integer" Value="1" KeyPath="yes"/>
Expand Down
4 changes: 2 additions & 2 deletions crates/packager/src/wix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -490,9 +490,9 @@ fn build_wix_app_installer(

data.insert("product_name", to_json(&config.product_name));
data.insert("version", to_json(&app_version));
let bundle_id = config.identifier();
let identifier = config.identifier();
let manufacturer = config.publisher();
data.insert("bundle_id", to_json(bundle_id));
data.insert("identifier", to_json(identifier));
data.insert("manufacturer", to_json(manufacturer));
let upgrade_code = Uuid::new_v5(
&Uuid::NAMESPACE_DNS,
Expand Down
1 change: 0 additions & 1 deletion examples/dioxus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ dioxus = "0.4"
dioxus-desktop = "0.4"

[package.metadata.packager]
out-dir = "./dist"
before-packaging-command = "dx build --platform desktop --release"
product-name = "Dioxus example"
identifier = "com.dioxus.example"
Expand Down
1 change: 1 addition & 0 deletions examples/tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ libs = [
"gtk" = "https://raw.githubusercontent.com/tauri-apps/linuxdeploy-plugin-gtk/master/linuxdeploy-plugin-gtk.sh"

[package.metadata.packager.nsis]
appdata-paths = ["$LOCALAPPDATA/$IDENTIFIER"]
preinstall-section = """
; Setup messages
; English
Expand Down

0 comments on commit 32d390c

Please sign in to comment.