mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-08-16 19:30:27 +03:00
refactor(cli): add --no-bundle
flag, skip bundling on invalid formats (#8990)
* refactor(cli): add `--no-bundle` flag, skip bundling on invalid formats * enhance bundle format parsing * lint [skip ci] --------- Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
This commit is contained in:
parent
4f78941763
commit
c68218b362
6
.changes/cli-build-no-bundle.md
Normal file
6
.changes/cli-build-no-bundle.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
'tauri-cli': 'patch:enhance'
|
||||||
|
'@tauri-apps/cli': 'patch:enhance'
|
||||||
|
---
|
||||||
|
|
||||||
|
Add `--no-bundle` flag for `tauri build` command to skip bundling. Previously `none` was used to skip bundling, it will now be treated as invalid format and a warning will be emitted instead.
|
5
.changes/utils-bundle-target-all.md
Normal file
5
.changes/utils-bundle-target-all.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'tauri-utils': 'patch:bug'
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix `BundleTarget::to_vec` returning an empty vec for `BundleTarget::All` variant.
|
5
.changes/utils-bundle-type-all.md
Normal file
5
.changes/utils-bundle-type-all.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'tauri-utils': 'patch:bug'
|
||||||
|
---
|
||||||
|
|
||||||
|
Add `BundleType::all` method to return all possible `BundleType` variants.
|
@ -121,6 +121,22 @@ pub enum BundleType {
|
|||||||
Updater,
|
Updater,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BundleType {
|
||||||
|
/// All bundle types.
|
||||||
|
fn all() -> &'static [Self] {
|
||||||
|
&[
|
||||||
|
BundleType::Deb,
|
||||||
|
BundleType::Rpm,
|
||||||
|
BundleType::AppImage,
|
||||||
|
BundleType::Msi,
|
||||||
|
BundleType::Nsis,
|
||||||
|
BundleType::App,
|
||||||
|
BundleType::Dmg,
|
||||||
|
BundleType::Updater,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for BundleType {
|
impl Display for BundleType {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
@ -274,7 +290,7 @@ impl BundleTarget {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn to_vec(&self) -> Vec<BundleType> {
|
pub fn to_vec(&self) -> Vec<BundleType> {
|
||||||
match self {
|
match self {
|
||||||
Self::All => vec![],
|
Self::All => BundleType::all().to_vec(),
|
||||||
Self::List(list) => list.clone(),
|
Self::List(list) => list.clone(),
|
||||||
Self::One(i) => vec![i.clone()],
|
Self::One(i) => vec![i.clone()],
|
||||||
}
|
}
|
||||||
|
16
examples/api/src-tauri/Cargo.lock
generated
16
examples/api/src-tauri/Cargo.lock
generated
@ -3151,7 +3151,7 @@ checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri"
|
name = "tauri"
|
||||||
version = "2.0.0-beta.7"
|
version = "2.0.0-beta.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -3202,7 +3202,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-build"
|
name = "tauri-build"
|
||||||
version = "2.0.0-beta.5"
|
version = "2.0.0-beta.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cargo_toml",
|
"cargo_toml",
|
||||||
@ -3224,7 +3224,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-codegen"
|
name = "tauri-codegen"
|
||||||
version = "2.0.0-beta.5"
|
version = "2.0.0-beta.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"brotli",
|
"brotli",
|
||||||
@ -3249,7 +3249,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-macros"
|
name = "tauri-macros"
|
||||||
version = "2.0.0-beta.5"
|
version = "2.0.0-beta.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@ -3261,7 +3261,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin"
|
name = "tauri-plugin"
|
||||||
version = "2.0.0-beta.5"
|
version = "2.0.0-beta.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"glob",
|
"glob",
|
||||||
@ -3287,7 +3287,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-runtime"
|
name = "tauri-runtime"
|
||||||
version = "2.0.0-beta.5"
|
version = "2.0.0-beta.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gtk",
|
"gtk",
|
||||||
"http",
|
"http",
|
||||||
@ -3303,7 +3303,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-runtime-wry"
|
name = "tauri-runtime-wry"
|
||||||
version = "2.0.0-beta.5"
|
version = "2.0.0-beta.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cocoa",
|
"cocoa",
|
||||||
"gtk",
|
"gtk",
|
||||||
@ -3324,7 +3324,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-utils"
|
name = "tauri-utils"
|
||||||
version = "2.0.0-beta.5"
|
version = "2.0.0-beta.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes-gcm",
|
"aes-gcm",
|
||||||
"brotli",
|
"brotli",
|
||||||
|
@ -6,7 +6,7 @@ use crate::{
|
|||||||
helpers::{
|
helpers::{
|
||||||
app_paths::{app_dir, tauri_dir},
|
app_paths::{app_dir, tauri_dir},
|
||||||
command_env,
|
command_env,
|
||||||
config::{get as get_config, ConfigHandle, FrontendDist, HookCommand},
|
config::{get as get_config, ConfigHandle, ConfigMetadata, FrontendDist, HookCommand},
|
||||||
updater_signature::{secret_key as updater_secret_key, sign_file},
|
updater_signature::{secret_key as updater_secret_key, sign_file},
|
||||||
},
|
},
|
||||||
interface::{AppInterface, AppSettings, Interface},
|
interface::{AppInterface, AppSettings, Interface},
|
||||||
@ -14,16 +14,40 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use anyhow::{bail, Context};
|
use anyhow::{bail, Context};
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use clap::{ArgAction, Parser};
|
use clap::{builder::PossibleValue, ArgAction, Parser, ValueEnum};
|
||||||
use log::{debug, error, info, warn};
|
|
||||||
use std::{
|
use std::{
|
||||||
env::{set_current_dir, var},
|
env::{set_current_dir, var},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
process::Command,
|
process::Command,
|
||||||
|
str::FromStr,
|
||||||
|
sync::OnceLock,
|
||||||
};
|
};
|
||||||
use tauri_bundler::bundle::{bundle_project, Bundle, PackageType};
|
use tauri_bundler::bundle::{bundle_project, Bundle, PackageType};
|
||||||
use tauri_utils::platform::Target;
|
use tauri_utils::platform::Target;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct BundleFormat(PackageType);
|
||||||
|
|
||||||
|
impl FromStr for BundleFormat {
|
||||||
|
type Err = anyhow::Error;
|
||||||
|
fn from_str(s: &str) -> Result<Self> {
|
||||||
|
PackageType::from_short_name(s)
|
||||||
|
.map(Self)
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("unknown bundle format {s}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ValueEnum for BundleFormat {
|
||||||
|
fn value_variants<'a>() -> &'a [Self] {
|
||||||
|
static VARIANTS: OnceLock<Vec<BundleFormat>> = OnceLock::new();
|
||||||
|
VARIANTS.get_or_init(|| PackageType::all().iter().map(|t| Self(*t)).collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_possible_value(&self) -> Option<PossibleValue> {
|
||||||
|
Some(PossibleValue::new(self.0.short_name()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Parser)]
|
#[derive(Debug, Clone, Parser)]
|
||||||
#[clap(
|
#[clap(
|
||||||
about = "Build your app in release mode and generate bundles and installers",
|
about = "Build your app in release mode and generate bundles and installers",
|
||||||
@ -48,12 +72,12 @@ pub struct Options {
|
|||||||
pub features: Option<Vec<String>>,
|
pub features: Option<Vec<String>>,
|
||||||
/// Space or comma separated list of bundles to package.
|
/// Space or comma separated list of bundles to package.
|
||||||
///
|
///
|
||||||
/// Each bundle must be one of `deb`, `rpm`, `appimage`, `msi`, `app` or `dmg` on MacOS and `updater` on all platforms.
|
|
||||||
/// If `none` is specified, the bundler will be skipped.
|
|
||||||
///
|
|
||||||
/// Note that the `updater` bundle is not automatically added so you must specify it if the updater is enabled.
|
/// Note that the `updater` bundle is not automatically added so you must specify it if the updater is enabled.
|
||||||
#[clap(short, long, action = ArgAction::Append, num_args(0..), value_delimiter = ',')]
|
#[clap(short, long, action = ArgAction::Append, num_args(0..), value_delimiter = ',')]
|
||||||
pub bundles: Option<Vec<String>>,
|
pub bundles: Option<Vec<BundleFormat>>,
|
||||||
|
/// Skip the bundling step even if `bundle > active` is `true` in tauri config.
|
||||||
|
#[clap(long)]
|
||||||
|
pub no_bundle: bool,
|
||||||
/// JSON string or path to JSON file to merge with tauri.conf.json
|
/// JSON string or path to JSON file to merge with tauri.conf.json
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
pub config: Option<ConfigValue>,
|
pub config: Option<ConfigValue>,
|
||||||
@ -95,171 +119,15 @@ pub fn command(mut options: Options, verbosity: u8) -> Result<()> {
|
|||||||
|
|
||||||
let app_settings = interface.app_settings();
|
let app_settings = interface.app_settings();
|
||||||
|
|
||||||
if config_.bundle.active {
|
bundle(
|
||||||
let package_types = if let Some(names) = &options.bundles {
|
&options,
|
||||||
let mut types = vec![];
|
verbosity,
|
||||||
let mut skip = false;
|
ci,
|
||||||
for name in names {
|
&interface,
|
||||||
if name == "none" {
|
&app_settings,
|
||||||
skip = true;
|
config_,
|
||||||
break;
|
out_dir,
|
||||||
}
|
)?;
|
||||||
|
|
||||||
match PackageType::from_short_name(name) {
|
|
||||||
Some(package_type) => {
|
|
||||||
types.push(package_type);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
return Err(anyhow::anyhow!(format!(
|
|
||||||
"Unsupported bundle format: {name}"
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if skip {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(types)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let targets = config_.bundle.targets.to_vec();
|
|
||||||
if targets.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(targets.into_iter().map(Into::into).collect())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let updater_pub_key = config_
|
|
||||||
.plugins
|
|
||||||
.0
|
|
||||||
.get("updater")
|
|
||||||
.and_then(|k| k.get("pubkey"))
|
|
||||||
.and_then(|v| v.as_str())
|
|
||||||
.map(|v| v.to_string());
|
|
||||||
if let Some(types) = &package_types {
|
|
||||||
if updater_pub_key
|
|
||||||
.as_ref()
|
|
||||||
.map(|v| !v.is_empty())
|
|
||||||
.unwrap_or(false)
|
|
||||||
&& !types.contains(&PackageType::Updater)
|
|
||||||
{
|
|
||||||
warn!("`plugins > updater > pubkey` is set, but the bundle target list does not contain `updater`, so the updater artifacts won't be generated.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we have a package to bundle, let's run the `before_bundle_command`.
|
|
||||||
if package_types.as_ref().map_or(true, |p| !p.is_empty()) {
|
|
||||||
if let Some(before_bundle) = config_.build.before_bundle_command.clone() {
|
|
||||||
run_hook(
|
|
||||||
"beforeBundleCommand",
|
|
||||||
before_bundle,
|
|
||||||
&interface,
|
|
||||||
options.debug,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut settings = app_settings
|
|
||||||
.get_bundler_settings(&options.into(), config_, out_dir, package_types)
|
|
||||||
.with_context(|| "failed to build bundler settings")?;
|
|
||||||
|
|
||||||
settings.set_log_level(match verbosity {
|
|
||||||
0 => log::Level::Error,
|
|
||||||
1 => log::Level::Info,
|
|
||||||
_ => log::Level::Trace,
|
|
||||||
});
|
|
||||||
|
|
||||||
// set env vars used by the bundler
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
{
|
|
||||||
if config_.bundle.linux.appimage.bundle_media_framework {
|
|
||||||
std::env::set_var("APPIMAGE_BUNDLE_GSTREAMER", "1");
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(open) = config_.plugins.0.get("shell").and_then(|v| v.get("open")) {
|
|
||||||
if open.as_bool().is_some_and(|x| x) || open.is_string() {
|
|
||||||
std::env::set_var("APPIMAGE_BUNDLE_XDG_OPEN", "1");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if settings.deep_link_protocols().is_some() {
|
|
||||||
std::env::set_var("APPIMAGE_BUNDLE_XDG_MIME", "1");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let bundles = bundle_project(settings)
|
|
||||||
.map_err(|e| anyhow::anyhow!("{:#}", e))
|
|
||||||
.with_context(|| "failed to bundle project")?;
|
|
||||||
|
|
||||||
let updater_bundles: Vec<&Bundle> = bundles
|
|
||||||
.iter()
|
|
||||||
.filter(|bundle| bundle.package_type == PackageType::Updater)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// If updater is active and we bundled it
|
|
||||||
if !updater_bundles.is_empty() {
|
|
||||||
if let Some(pubkey) = updater_pub_key {
|
|
||||||
// get the public key
|
|
||||||
// check if pubkey points to a file...
|
|
||||||
let maybe_path = Path::new(&pubkey);
|
|
||||||
let pubkey = if maybe_path.exists() {
|
|
||||||
std::fs::read_to_string(maybe_path)?
|
|
||||||
} else {
|
|
||||||
pubkey
|
|
||||||
};
|
|
||||||
|
|
||||||
// if no password provided we use an empty string
|
|
||||||
let password = var("TAURI_SIGNING_PRIVATE_KEY_PASSWORD").ok().or_else(|| {
|
|
||||||
if ci {
|
|
||||||
Some("".into())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// get the private key
|
|
||||||
let secret_key = match var("TAURI_SIGNING_PRIVATE_KEY") {
|
|
||||||
Ok(private_key) => {
|
|
||||||
// check if private_key points to a file...
|
|
||||||
let maybe_path = Path::new(&private_key);
|
|
||||||
let private_key = if maybe_path.exists() {
|
|
||||||
std::fs::read_to_string(maybe_path)?
|
|
||||||
} else {
|
|
||||||
private_key
|
|
||||||
};
|
|
||||||
updater_secret_key(private_key, password)
|
|
||||||
}
|
|
||||||
_ => Err(anyhow::anyhow!("A public key has been found, but no private key. Make sure to set `TAURI_SIGNING_PRIVATE_KEY` environment variable.")),
|
|
||||||
}?;
|
|
||||||
|
|
||||||
let pubkey = base64::engine::general_purpose::STANDARD.decode(pubkey)?;
|
|
||||||
let pub_key_decoded = String::from_utf8_lossy(&pubkey);
|
|
||||||
let public_key =
|
|
||||||
minisign::PublicKeyBox::from_string(&pub_key_decoded)?.into_public_key()?;
|
|
||||||
|
|
||||||
// make sure we have our package built
|
|
||||||
let mut signed_paths = Vec::new();
|
|
||||||
for elem in updater_bundles {
|
|
||||||
// we expect to have only one path in the vec but we iter if we add
|
|
||||||
// another type of updater package who require multiple file signature
|
|
||||||
for path in elem.bundle_paths.iter() {
|
|
||||||
// sign our path from environment variables
|
|
||||||
let (signature_path, signature) = sign_file(&secret_key, path)?;
|
|
||||||
if signature.keynum() != public_key.keynum() {
|
|
||||||
log::warn!(
|
|
||||||
"The updater secret key from `TAURI_PRIVATE_KEY` does not match the public key from `plugins > updater > pubkey`. If you are not rotating keys, this means your configuration is wrong and won't be accepted at runtime when performing update."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
signed_paths.push(signature_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
print_signed_updater_archive(&signed_paths)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -281,7 +149,7 @@ pub fn setup(
|
|||||||
.unwrap_or_else(|| "tauri.conf.json".into());
|
.unwrap_or_else(|| "tauri.conf.json".into());
|
||||||
|
|
||||||
if config_.identifier == "com.tauri.dev" {
|
if config_.identifier == "com.tauri.dev" {
|
||||||
error!(
|
log::error!(
|
||||||
"You must change the bundle identifier in `{} identifier`. The default value `com.tauri.dev` is not allowed as it must be unique across applications.",
|
"You must change the bundle identifier in `{} identifier`. The default value `com.tauri.dev` is not allowed as it must be unique across applications.",
|
||||||
bundle_identifier_source
|
bundle_identifier_source
|
||||||
);
|
);
|
||||||
@ -293,7 +161,7 @@ pub fn setup(
|
|||||||
.chars()
|
.chars()
|
||||||
.any(|ch| !(ch.is_alphanumeric() || ch == '-' || ch == '.'))
|
.any(|ch| !(ch.is_alphanumeric() || ch == '-' || ch == '.'))
|
||||||
{
|
{
|
||||||
error!(
|
log::error!(
|
||||||
"The bundle identifier \"{}\" set in `{} identifier`. The bundle identifier string must contain only alphanumeric characters (A-Z, a-z, and 0-9), hyphens (-), and periods (.).",
|
"The bundle identifier \"{}\" set in `{} identifier`. The bundle identifier string must contain only alphanumeric characters (A-Z, a-z, and 0-9), hyphens (-), and periods (.).",
|
||||||
config_.identifier,
|
config_.identifier,
|
||||||
bundle_identifier_source
|
bundle_identifier_source
|
||||||
@ -347,6 +215,165 @@ pub fn setup(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bundle<A: AppSettings>(
|
||||||
|
options: &Options,
|
||||||
|
verbosity: u8,
|
||||||
|
ci: bool,
|
||||||
|
interface: &AppInterface,
|
||||||
|
app_settings: &std::sync::Arc<A>,
|
||||||
|
config: &ConfigMetadata,
|
||||||
|
out_dir: &Path,
|
||||||
|
) -> crate::Result<()> {
|
||||||
|
if options.no_bundle || (options.bundles.is_none() && !config.bundle.active) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let package_types: Vec<PackageType> = if let Some(bundles) = &options.bundles {
|
||||||
|
bundles.iter().map(|bundle| bundle.0).collect::<Vec<_>>()
|
||||||
|
} else {
|
||||||
|
config
|
||||||
|
.bundle
|
||||||
|
.targets
|
||||||
|
.to_vec()
|
||||||
|
.into_iter()
|
||||||
|
.map(Into::into)
|
||||||
|
.collect()
|
||||||
|
};
|
||||||
|
|
||||||
|
if package_types.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let updater_pub_key = config
|
||||||
|
.plugins
|
||||||
|
.0
|
||||||
|
.get("updater")
|
||||||
|
.and_then(|k| k.get("pubkey"))
|
||||||
|
.and_then(|v| v.as_str())
|
||||||
|
.map(|v| v.to_string());
|
||||||
|
|
||||||
|
if updater_pub_key
|
||||||
|
.as_ref()
|
||||||
|
.map(|v| !v.is_empty())
|
||||||
|
.unwrap_or(false)
|
||||||
|
&& !package_types.contains(&PackageType::Updater)
|
||||||
|
{
|
||||||
|
log::warn!("`plugins > updater > pubkey` is set, but the bundle target list does not contain `updater`, so the updater artifacts won't be generated.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we have a package to bundle, let's run the `before_bundle_command`.
|
||||||
|
if !package_types.is_empty() {
|
||||||
|
if let Some(before_bundle) = config.build.before_bundle_command.clone() {
|
||||||
|
run_hook(
|
||||||
|
"beforeBundleCommand",
|
||||||
|
before_bundle,
|
||||||
|
interface,
|
||||||
|
options.debug,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut settings = app_settings
|
||||||
|
.get_bundler_settings(options.clone().into(), config, out_dir, package_types)
|
||||||
|
.with_context(|| "failed to build bundler settings")?;
|
||||||
|
|
||||||
|
settings.set_log_level(match verbosity {
|
||||||
|
0 => log::Level::Error,
|
||||||
|
1 => log::Level::Info,
|
||||||
|
_ => log::Level::Trace,
|
||||||
|
});
|
||||||
|
|
||||||
|
// set env vars used by the bundler
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
if config.bundle.linux.appimage.bundle_media_framework {
|
||||||
|
std::env::set_var("APPIMAGE_BUNDLE_GSTREAMER", "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(open) = config.plugins.0.get("shell").and_then(|v| v.get("open")) {
|
||||||
|
if open.as_bool().is_some_and(|x| x) || open.is_string() {
|
||||||
|
std::env::set_var("APPIMAGE_BUNDLE_XDG_OPEN", "1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.deep_link_protocols().is_some() {
|
||||||
|
std::env::set_var("APPIMAGE_BUNDLE_XDG_MIME", "1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let bundles = bundle_project(settings)
|
||||||
|
.map_err(|e| anyhow::anyhow!("{:#}", e))
|
||||||
|
.with_context(|| "failed to bundle project")?;
|
||||||
|
|
||||||
|
let updater_bundles: Vec<&Bundle> = bundles
|
||||||
|
.iter()
|
||||||
|
.filter(|bundle| bundle.package_type == PackageType::Updater)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// If updater is active and we bundled it
|
||||||
|
if !updater_bundles.is_empty() {
|
||||||
|
if let Some(pubkey) = updater_pub_key {
|
||||||
|
// get the public key
|
||||||
|
// check if pubkey points to a file...
|
||||||
|
let maybe_path = Path::new(&pubkey);
|
||||||
|
let pubkey = if maybe_path.exists() {
|
||||||
|
std::fs::read_to_string(maybe_path)?
|
||||||
|
} else {
|
||||||
|
pubkey
|
||||||
|
};
|
||||||
|
|
||||||
|
// if no password provided we use an empty string
|
||||||
|
let password = var("TAURI_SIGNING_PRIVATE_KEY_PASSWORD").ok().or_else(|| {
|
||||||
|
if ci {
|
||||||
|
Some("".into())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// get the private key
|
||||||
|
let secret_key = match var("TAURI_SIGNING_PRIVATE_KEY") {
|
||||||
|
Ok(private_key) => {
|
||||||
|
// check if private_key points to a file...
|
||||||
|
let maybe_path = Path::new(&private_key);
|
||||||
|
let private_key = if maybe_path.exists() {
|
||||||
|
std::fs::read_to_string(maybe_path)?
|
||||||
|
} else {
|
||||||
|
private_key
|
||||||
|
};
|
||||||
|
updater_secret_key(private_key, password)
|
||||||
|
}
|
||||||
|
_ => Err(anyhow::anyhow!("A public key has been found, but no private key. Make sure to set `TAURI_SIGNING_PRIVATE_KEY` environment variable.")),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
let pubkey = base64::engine::general_purpose::STANDARD.decode(pubkey)?;
|
||||||
|
let pub_key_decoded = String::from_utf8_lossy(&pubkey);
|
||||||
|
let public_key = minisign::PublicKeyBox::from_string(&pub_key_decoded)?.into_public_key()?;
|
||||||
|
|
||||||
|
// make sure we have our package built
|
||||||
|
let mut signed_paths = Vec::new();
|
||||||
|
for elem in updater_bundles {
|
||||||
|
// we expect to have only one path in the vec but we iter if we add
|
||||||
|
// another type of updater package who require multiple file signature
|
||||||
|
for path in elem.bundle_paths.iter() {
|
||||||
|
// sign our path from environment variables
|
||||||
|
let (signature_path, signature) = sign_file(&secret_key, path)?;
|
||||||
|
if signature.keynum() != public_key.keynum() {
|
||||||
|
log::warn!(
|
||||||
|
"The updater secret key from `TAURI_PRIVATE_KEY` does not match the public key from `plugins > updater > pubkey`. If you are not rotating keys, this means your configuration is wrong and won't be accepted at runtime when performing update."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
signed_paths.push(signature_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print_signed_updater_archive(&signed_paths)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn run_hook(name: &str, hook: HookCommand, interface: &AppInterface, debug: bool) -> Result<()> {
|
fn run_hook(name: &str, hook: HookCommand, interface: &AppInterface, debug: bool) -> Result<()> {
|
||||||
let (script, script_cwd) = match hook {
|
let (script, script_cwd) = match hook {
|
||||||
HookCommand::Script(s) if s.is_empty() => (None, None),
|
HookCommand::Script(s) if s.is_empty() => (None, None),
|
||||||
@ -355,12 +382,12 @@ fn run_hook(name: &str, hook: HookCommand, interface: &AppInterface, debug: bool
|
|||||||
};
|
};
|
||||||
let cwd = script_cwd.unwrap_or_else(|| app_dir().clone());
|
let cwd = script_cwd.unwrap_or_else(|| app_dir().clone());
|
||||||
if let Some(script) = script {
|
if let Some(script) = script {
|
||||||
info!(action = "Running"; "{} `{}`", name, script);
|
log::info!(action = "Running"; "{} `{}`", name, script);
|
||||||
|
|
||||||
let mut env = command_env(debug);
|
let mut env = command_env(debug);
|
||||||
env.extend(interface.env());
|
env.extend(interface.env());
|
||||||
|
|
||||||
debug!("Setting environment for hook {:?}", env);
|
log::debug!("Setting environment for hook {:?}", env);
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
let status = Command::new("cmd")
|
let status = Command::new("cmd")
|
||||||
@ -409,7 +436,7 @@ fn print_signed_updater_archive(output_paths: &[PathBuf]) -> crate::Result<()> {
|
|||||||
tauri_utils::display_path(path)
|
tauri_utils::display_path(path)
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
info!( action = "Finished"; "{} {} at:\n{}", output_paths.len(), pluralised, printable_paths);
|
log::info!( action = "Finished"; "{} {} at:\n{}", output_paths.len(), pluralised, printable_paths);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -41,10 +41,10 @@ pub trait AppSettings {
|
|||||||
|
|
||||||
fn get_bundler_settings(
|
fn get_bundler_settings(
|
||||||
&self,
|
&self,
|
||||||
options: &Options,
|
options: Options,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
out_dir: &Path,
|
out_dir: &Path,
|
||||||
package_types: Option<Vec<PackageType>>,
|
package_types: Vec<PackageType>,
|
||||||
) -> crate::Result<Settings> {
|
) -> crate::Result<Settings> {
|
||||||
let no_default_features = options.args.contains(&"--no-default-features".into());
|
let no_default_features = options.args.contains(&"--no-default-features".into());
|
||||||
let mut enabled_features = options.features.clone().unwrap_or_default();
|
let mut enabled_features = options.features.clone().unwrap_or_default();
|
||||||
@ -58,18 +58,15 @@ pub trait AppSettings {
|
|||||||
tauri_utils::platform::target_triple()?
|
tauri_utils::platform::target_triple()?
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut settings_builder = SettingsBuilder::new()
|
SettingsBuilder::new()
|
||||||
.package_settings(self.get_package_settings())
|
.package_settings(self.get_package_settings())
|
||||||
.bundle_settings(self.get_bundle_settings(config, &enabled_features)?)
|
.bundle_settings(self.get_bundle_settings(config, &enabled_features)?)
|
||||||
.binaries(self.get_binaries(config, &target)?)
|
.binaries(self.get_binaries(config, &target)?)
|
||||||
.project_out_directory(out_dir)
|
.project_out_directory(out_dir)
|
||||||
.target(target);
|
.target(target)
|
||||||
|
.package_types(package_types)
|
||||||
if let Some(types) = package_types {
|
.build()
|
||||||
settings_builder = settings_builder.package_types(types);
|
.map_err(Into::into)
|
||||||
}
|
|
||||||
|
|
||||||
settings_builder.build().map_err(Into::into)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +77,7 @@ impl From<Options> for BuildOptions {
|
|||||||
target: None,
|
target: None,
|
||||||
features: options.features,
|
features: options.features,
|
||||||
bundles: None,
|
bundles: None,
|
||||||
|
no_bundle: false,
|
||||||
config: options.config,
|
config: options.config,
|
||||||
args: Vec::new(),
|
args: Vec::new(),
|
||||||
ci: options.ci,
|
ci: options.ci,
|
||||||
|
@ -73,6 +73,7 @@ impl From<Options> for BuildOptions {
|
|||||||
target: None,
|
target: None,
|
||||||
features: options.features,
|
features: options.features,
|
||||||
bundles: None,
|
bundles: None,
|
||||||
|
no_bundle: false,
|
||||||
config: options.config,
|
config: options.config,
|
||||||
args: Vec::new(),
|
args: Vec::new(),
|
||||||
ci: options.ci,
|
ci: options.ci,
|
||||||
|
Loading…
Reference in New Issue
Block a user