Skip to content

Commit 911242f

Browse files
Legend-Masteramrbashirlucasfernog-crabnebulalucasfernog
authored
feat!(core): add bundle createUpdaterArtifacts configuration (#9883)
* Add updater field * Don't sign updaters when updater field is false * Clippy * Add updater to bundle migration * Format * Add updater config to api example * No warning if update is not enabled * Build * Add change file * We don't generate updater for dmg package * Warning only for v1 compatible * clean up * More clean up * little bit more * Apply suggestions from code review Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com> * Revert license header change * Remove option around pubkey and msi args * More migration tests * Refactor private_key getter * Only generate signature for updater for v1 compat * Format * Use map_err instead of anyhow context * Don't generate updater for api example * Fix misaligned comment * Rename `updater` to `createUpdaterArtifacts` * Revert changes in helloworld example * Add warning for v1 compatible * Update .changes/separate-updater-field.md Co-authored-by: Lucas Nogueira <118899497+lucasfernog-crabnebula@users.noreply.github.com> * update error messages [skip ci] --------- Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com> Co-authored-by: Lucas Nogueira <118899497+lucasfernog-crabnebula@users.noreply.github.com> Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
1 parent e7fd7c6 commit 911242f

File tree

10 files changed

+348
-155
lines changed

10 files changed

+348
-155
lines changed

.changes/separate-updater-field.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"tauri-utils": patch:breaking
3+
"tauri-bundler": patch:breaking
4+
"tauri-cli": patch:breaking
5+
"@tauri-apps/cli": patch:breaking
6+
---
7+
8+
Move updater target from `bundle > targets` to a separate field `bundle > createUpdaterArtifacts`

core/tauri-config-schema/schema.json

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
"android": {
7373
"minSdkVersion": 24
7474
},
75+
"createUpdaterArtifacts": false,
7576
"iOS": {},
7677
"icon": [],
7778
"linux": {
@@ -1519,14 +1520,23 @@
15191520
"type": "boolean"
15201521
},
15211522
"targets": {
1522-
"description": "The bundle targets, currently supports [\"deb\", \"rpm\", \"appimage\", \"nsis\", \"msi\", \"app\", \"dmg\", \"updater\"] or \"all\".",
1523+
"description": "The bundle targets, currently supports [\"deb\", \"rpm\", \"appimage\", \"nsis\", \"msi\", \"app\", \"dmg\"] or \"all\".",
15231524
"default": "all",
15241525
"allOf": [
15251526
{
15261527
"$ref": "#/definitions/BundleTarget"
15271528
}
15281529
]
15291530
},
1531+
"createUpdaterArtifacts": {
1532+
"description": "Produce updaters and their signatures or not",
1533+
"default": false,
1534+
"allOf": [
1535+
{
1536+
"$ref": "#/definitions/Updater"
1537+
}
1538+
]
1539+
},
15301540
"publisher": {
15311541
"description": "The application's publisher. Defaults to the second element in the identifier string.\n Currently maps to the Manufacturer property of the Windows Installer.",
15321542
"type": [
@@ -1794,12 +1804,34 @@
17941804
"enum": [
17951805
"dmg"
17961806
]
1807+
}
1808+
]
1809+
},
1810+
"Updater": {
1811+
"description": "Updater type",
1812+
"anyOf": [
1813+
{
1814+
"description": "Generates lagacy zipped v1 compatible updaters",
1815+
"allOf": [
1816+
{
1817+
"$ref": "#/definitions/V1Compatible"
1818+
}
1819+
]
17971820
},
17981821
{
1799-
"description": "The Tauri updater bundle.",
1822+
"description": "Produce updaters and their signatures or not",
1823+
"type": "boolean"
1824+
}
1825+
]
1826+
},
1827+
"V1Compatible": {
1828+
"description": "Generates lagacy zipped v1 compatible updaters",
1829+
"oneOf": [
1830+
{
1831+
"description": "Generates lagacy zipped v1 compatible updaters",
18001832
"type": "string",
18011833
"enum": [
1802-
"updater"
1834+
"v1Compatible"
18031835
]
18041836
}
18051837
]

core/tauri-utils/src/config.rs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,6 @@ pub enum BundleType {
116116
App,
117117
/// The Apple Disk Image bundle (.dmg).
118118
Dmg,
119-
/// The Tauri updater bundle.
120-
Updater,
121119
}
122120

123121
impl BundleType {
@@ -131,7 +129,6 @@ impl BundleType {
131129
BundleType::Nsis,
132130
BundleType::App,
133131
BundleType::Dmg,
134-
BundleType::Updater,
135132
]
136133
}
137134
}
@@ -149,7 +146,6 @@ impl Display for BundleType {
149146
Self::Nsis => "nsis",
150147
Self::App => "app",
151148
Self::Dmg => "dmg",
152-
Self::Updater => "updater",
153149
}
154150
)
155151
}
@@ -178,7 +174,6 @@ impl<'de> Deserialize<'de> for BundleType {
178174
"nsis" => Ok(Self::Nsis),
179175
"app" => Ok(Self::App),
180176
"dmg" => Ok(Self::Dmg),
181-
"updater" => Ok(Self::Updater),
182177
_ => Err(DeError::custom(format!("unknown bundle target '{s}'"))),
183178
}
184179
}
@@ -1070,6 +1065,33 @@ impl BundleResources {
10701065
}
10711066
}
10721067

1068+
/// Updater type
1069+
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
1070+
#[cfg_attr(feature = "schema", derive(JsonSchema))]
1071+
#[serde(rename_all = "camelCase", deny_unknown_fields, untagged)]
1072+
pub enum Updater {
1073+
/// Generates lagacy zipped v1 compatible updaters
1074+
String(V1Compatible),
1075+
/// Produce updaters and their signatures or not
1076+
// Can't use untagged on enum field here: https://github.com/GREsau/schemars/issues/222
1077+
Bool(bool),
1078+
}
1079+
1080+
impl Default for Updater {
1081+
fn default() -> Self {
1082+
Self::Bool(false)
1083+
}
1084+
}
1085+
1086+
/// Generates lagacy zipped v1 compatible updaters
1087+
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
1088+
#[cfg_attr(feature = "schema", derive(JsonSchema))]
1089+
#[serde(rename_all = "camelCase", deny_unknown_fields)]
1090+
pub enum V1Compatible {
1091+
/// Generates lagacy zipped v1 compatible updaters
1092+
V1Compatible,
1093+
}
1094+
10731095
/// Configuration for tauri-bundler.
10741096
///
10751097
/// See more: <https://tauri.app/v1/api/config#bundleconfig>
@@ -1081,9 +1103,12 @@ pub struct BundleConfig {
10811103
/// Whether Tauri should bundle your application or just output the executable.
10821104
#[serde(default)]
10831105
pub active: bool,
1084-
/// The bundle targets, currently supports ["deb", "rpm", "appimage", "nsis", "msi", "app", "dmg", "updater"] or "all".
1106+
/// The bundle targets, currently supports ["deb", "rpm", "appimage", "nsis", "msi", "app", "dmg"] or "all".
10851107
#[serde(default)]
10861108
pub targets: BundleTarget,
1109+
#[serde(default)]
1110+
/// Produce updaters and their signatures or not
1111+
pub create_updater_artifacts: Updater,
10871112
/// The application's publisher. Defaults to the second element in the identifier string.
10881113
/// Currently maps to the Manufacturer property of the Windows Installer.
10891114
pub publisher: Option<String>,
@@ -2474,6 +2499,7 @@ mod build {
24742499
let icon = vec_lit(&self.icon, str_lit);
24752500
let active = self.active;
24762501
let targets = quote!(Default::default());
2502+
let create_updater_artifacts = quote!(Default::default());
24772503
let resources = quote!(None);
24782504
let copyright = quote!(None);
24792505
let category = quote!(None);
@@ -2497,6 +2523,7 @@ mod build {
24972523
homepage,
24982524
icon,
24992525
targets,
2526+
create_updater_artifacts,
25002527
resources,
25012528
copyright,
25022529
category,
@@ -2811,6 +2838,7 @@ mod test {
28112838
let bundle = BundleConfig {
28122839
active: false,
28132840
targets: Default::default(),
2841+
create_updater_artifacts: Default::default(),
28142842
publisher: None,
28152843
homepage: None,
28162844
icon: Vec::new(),

tooling/bundler/src/bundle.rs

Lines changed: 66 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,14 @@ pub struct Bundle {
4242

4343
/// Bundles the project.
4444
/// Returns the list of paths where the bundles can be found.
45-
pub fn bundle_project(settings: Settings) -> crate::Result<Vec<Bundle>> {
45+
pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<Bundle>> {
4646
let mut package_types = settings.package_types()?;
4747
if package_types.is_empty() {
4848
return Ok(Vec::new());
4949
}
5050

5151
package_types.sort_by_key(|a| a.priority());
5252

53-
let mut bundles: Vec<Bundle> = Vec::new();
54-
5553
let target_os = settings
5654
.target()
5755
.split('-')
@@ -68,7 +66,7 @@ pub fn bundle_project(settings: Settings) -> crate::Result<Vec<Bundle>> {
6866
if settings.can_sign() {
6967
for bin in settings.binaries() {
7068
let bin_path = settings.binary_path(bin);
71-
windows::sign::try_sign(&bin_path, &settings)?;
69+
windows::sign::try_sign(&bin_path, settings)?;
7270
}
7371

7472
// Sign the sidecar binaries
@@ -89,14 +87,15 @@ pub fn bundle_project(settings: Settings) -> crate::Result<Vec<Bundle>> {
8987
continue;
9088
}
9189

92-
windows::sign::try_sign(&path, &settings)?;
90+
windows::sign::try_sign(&path, settings)?;
9391
}
9492
} else {
9593
#[cfg(not(target_os = "windows"))]
9694
log::warn!("Signing, by default, is only supported on Windows hosts, but you can specify a custom signing command in `bundler > windows > sign_command`, for now, skipping signing the installer...");
9795
}
9896
}
9997

98+
let mut bundles = Vec::<Bundle>::new();
10099
for package_type in &package_types {
101100
// bundle was already built! e.g. DMG already built .app
102101
if bundles.iter().any(|b| b.package_type == *package_type) {
@@ -105,13 +104,13 @@ pub fn bundle_project(settings: Settings) -> crate::Result<Vec<Bundle>> {
105104

106105
let bundle_paths = match package_type {
107106
#[cfg(target_os = "macos")]
108-
PackageType::MacOsBundle => macos::app::bundle_project(&settings)?,
107+
PackageType::MacOsBundle => macos::app::bundle_project(settings)?,
109108
#[cfg(target_os = "macos")]
110-
PackageType::IosBundle => macos::ios::bundle_project(&settings)?,
109+
PackageType::IosBundle => macos::ios::bundle_project(settings)?,
111110
// dmg is dependent of MacOsBundle, we send our bundles to prevent rebuilding
112111
#[cfg(target_os = "macos")]
113112
PackageType::Dmg => {
114-
let bundled = macos::dmg::bundle_project(&settings, &bundles)?;
113+
let bundled = macos::dmg::bundle_project(settings, &bundles)?;
115114
if !bundled.app.is_empty() {
116115
bundles.push(Bundle {
117116
package_type: PackageType::MacOsBundle,
@@ -122,33 +121,15 @@ pub fn bundle_project(settings: Settings) -> crate::Result<Vec<Bundle>> {
122121
}
123122

124123
#[cfg(target_os = "windows")]
125-
PackageType::WindowsMsi => windows::msi::bundle_project(&settings, false)?,
126-
PackageType::Nsis => windows::nsis::bundle_project(&settings, false)?,
124+
PackageType::WindowsMsi => windows::msi::bundle_project(settings, false)?,
125+
PackageType::Nsis => windows::nsis::bundle_project(settings, false)?,
127126

128127
#[cfg(target_os = "linux")]
129-
PackageType::Deb => linux::debian::bundle_project(&settings)?,
128+
PackageType::Deb => linux::debian::bundle_project(settings)?,
130129
#[cfg(target_os = "linux")]
131-
PackageType::Rpm => linux::rpm::bundle_project(&settings)?,
130+
PackageType::Rpm => linux::rpm::bundle_project(settings)?,
132131
#[cfg(target_os = "linux")]
133-
PackageType::AppImage => linux::appimage::bundle_project(&settings)?,
134-
135-
// updater is dependent of multiple bundle, we send our bundles to prevent rebuilding
136-
PackageType::Updater => {
137-
if !package_types.iter().any(|p| {
138-
matches!(
139-
p,
140-
PackageType::AppImage
141-
| PackageType::MacOsBundle
142-
| PackageType::Dmg
143-
| PackageType::Nsis
144-
| PackageType::WindowsMsi
145-
)
146-
}) {
147-
log::warn!("The updater bundle target exists but couldn't find any updater-enabled target, so the updater artifacts won't be generated. Please add one of these targets as well: app, appimage, msi, nsis");
148-
continue;
149-
}
150-
updater_bundle::bundle_project(&settings, &bundles)?
151-
}
132+
PackageType::AppImage => linux::appimage::bundle_project(settings)?,
152133
_ => {
153134
log::warn!("ignoring {}", package_type.short_name());
154135
continue;
@@ -161,6 +142,33 @@ pub fn bundle_project(settings: Settings) -> crate::Result<Vec<Bundle>> {
161142
});
162143
}
163144

145+
if let Some(updater) = settings.updater() {
146+
if package_types.iter().any(|package_type| {
147+
if updater.v1_compatible {
148+
matches!(
149+
package_type,
150+
PackageType::AppImage
151+
| PackageType::MacOsBundle
152+
| PackageType::Nsis
153+
| PackageType::WindowsMsi
154+
)
155+
} else {
156+
matches!(package_type, PackageType::MacOsBundle)
157+
}
158+
}) {
159+
let updater_paths = updater_bundle::bundle_project(settings, &bundles)?;
160+
bundles.push(Bundle {
161+
package_type: PackageType::Updater,
162+
bundle_paths: updater_paths,
163+
});
164+
} else if updater.v1_compatible {
165+
log::warn!("The updater bundle target exists but couldn't find any updater-enabled target, so the updater artifacts won't be generated. Please add one of these targets as well: app, appimage, msi, nsis");
166+
}
167+
if updater.v1_compatible {
168+
log::warn!("Legacy v1 compatible updater is deprecated and will be removed in v3, change bundle > createUpdaterArtifacts to true when your users are updated to the version with v2 updater plugin");
169+
}
170+
}
171+
164172
#[cfg(target_os = "macos")]
165173
{
166174
// Clean up .app if only building dmg or updater
@@ -188,34 +196,37 @@ pub fn bundle_project(settings: Settings) -> crate::Result<Vec<Bundle>> {
188196
}
189197
}
190198

191-
if !bundles.is_empty() {
192-
let bundles_wo_updater = bundles
193-
.iter()
194-
.filter(|b| b.package_type != PackageType::Updater)
195-
.collect::<Vec<_>>();
196-
let pluralised = if bundles_wo_updater.len() == 1 {
197-
"bundle"
198-
} else {
199-
"bundles"
200-
};
199+
if bundles.is_empty() {
200+
return Err(anyhow::anyhow!("No bundles were built").into());
201+
}
201202

202-
let mut printable_paths = String::new();
203-
for bundle in &bundles {
204-
for path in &bundle.bundle_paths {
205-
let mut note = "";
206-
if bundle.package_type == crate::PackageType::Updater {
207-
note = " (updater)";
208-
}
209-
writeln!(printable_paths, " {}{}", display_path(path), note).unwrap();
210-
}
203+
let bundles_wo_updater = bundles
204+
.iter()
205+
.filter(|b| b.package_type != PackageType::Updater)
206+
.collect::<Vec<_>>();
207+
let finished_bundles = bundles_wo_updater.len();
208+
let pluralised = if finished_bundles == 1 {
209+
"bundle"
210+
} else {
211+
"bundles"
212+
};
213+
214+
let mut printable_paths = String::new();
215+
for bundle in &bundles {
216+
for path in &bundle.bundle_paths {
217+
let note = if bundle.package_type == crate::PackageType::Updater {
218+
" (updater)"
219+
} else {
220+
""
221+
};
222+
let path_display = display_path(path);
223+
writeln!(printable_paths, " {path_display}{note}").unwrap();
211224
}
225+
}
212226

213-
log::info!(action = "Finished"; "{} {} at:\n{}", bundles_wo_updater.len(), pluralised, printable_paths);
227+
log::info!(action = "Finished"; "{finished_bundles} {pluralised} at:\n{printable_paths}");
214228

215-
Ok(bundles)
216-
} else {
217-
Err(anyhow::anyhow!("No bundles were built").into())
218-
}
229+
Ok(bundles)
219230
}
220231

221232
/// Check to see if there are icons in the settings struct

0 commit comments

Comments
 (0)