@ -4,6 +4,7 @@
use std ::{
use std ::{
collections ::HashMap ,
collections ::HashMap ,
ffi ::{ OsStr , OsString } ,
io ::{ Cursor , Read } ,
io ::{ Cursor , Read } ,
path ::{ Path , PathBuf } ,
path ::{ Path , PathBuf } ,
str ::FromStr ,
str ::FromStr ,
@ -20,14 +21,14 @@ use reqwest::{
} ;
} ;
use semver ::Version ;
use semver ::Version ;
use serde ::{ de ::Error as DeError , Deserialize , Deserializer , Serialize } ;
use serde ::{ de ::Error as DeError , Deserialize , Deserializer , Serialize } ;
use tauri ::{
use tauri ::{ utils ::platform ::current_exe , Resource } ;
utils ::{ config ::UpdaterConfig , platform ::current_exe } ,
Resource ,
} ;
use time ::OffsetDateTime ;
use time ::OffsetDateTime ;
use url ::Url ;
use url ::Url ;
use crate ::error ::{ Error , Result } ;
use crate ::{
error ::{ Error , Result } ,
Config ,
} ;
#[ derive(Debug, Deserialize, Serialize, Clone) ]
#[ derive(Debug, Deserialize, Serialize, Clone) ]
pub struct ReleaseManifestPlatform {
pub struct ReleaseManifestPlatform {
@ -89,8 +90,7 @@ impl RemoteRelease {
pub struct UpdaterBuilder {
pub struct UpdaterBuilder {
current_version : Version ,
current_version : Version ,
config : crate ::Config ,
config : Config ,
updater_config : UpdaterConfig ,
version_comparator : Option < Box < dyn Fn ( Version , RemoteRelease ) -> bool + Send + Sync > > ,
version_comparator : Option < Box < dyn Fn ( Version , RemoteRelease ) -> bool + Send + Sync > > ,
executable_path : Option < PathBuf > ,
executable_path : Option < PathBuf > ,
target : Option < String > ,
target : Option < String > ,
@ -98,19 +98,19 @@ pub struct UpdaterBuilder {
headers : HeaderMap ,
headers : HeaderMap ,
timeout : Option < Duration > ,
timeout : Option < Duration > ,
proxy : Option < Url > ,
proxy : Option < Url > ,
installer_args : Option< Vec < String > > ,
installer_args : Vec< OsString > ,
}
}
impl UpdaterBuilder {
impl UpdaterBuilder {
pub fn new (
pub fn new ( current_version : Version , config : crate ::Config ) -> Self {
current_version : Version ,
config : crate ::Config ,
updater_config : UpdaterConfig ,
) -> Self {
Self {
Self {
installer_args : config
. windows
. as_ref ( )
. map ( | w | w . installer_args . clone ( ) )
. unwrap_or_default ( ) ,
current_version ,
current_version ,
config ,
config ,
updater_config ,
version_comparator : None ,
version_comparator : None ,
executable_path : None ,
executable_path : None ,
target : None ,
target : None ,
@ -118,7 +118,6 @@ impl UpdaterBuilder {
headers : Default ::default ( ) ,
headers : Default ::default ( ) ,
timeout : None ,
timeout : None ,
proxy : None ,
proxy : None ,
installer_args : None ,
}
}
}
}
@ -170,20 +169,41 @@ impl UpdaterBuilder {
self
self
}
}
pub fn pubkey < S : Into < String > > ( mut self , pubkey : S ) -> Self {
self . config . pubkey = pubkey . into ( ) ;
self
}
pub fn installer_arg < S > ( mut self , arg : S ) -> Self
where
S : AsRef < OsStr > ,
{
self . installer_args . push ( arg . as_ref ( ) . to_os_string ( ) ) ;
self
}
pub fn installer_args < I , S > ( mut self , args : I ) -> Self
pub fn installer_args < I , S > ( mut self , args : I ) -> Self
where
where
I : IntoIterator < Item = S > ,
I : IntoIterator < Item = S > ,
S : Into < String > ,
S : AsRef< OsStr > ,
{
{
self . installer_args
let args = args
. replace ( args . into_iter ( ) . map ( Into ::into ) . collect ( ) ) ;
. into_iter ( )
. map ( | a | a . as_ref ( ) . to_os_string ( ) )
. collect ::< Vec < _ > > ( ) ;
self . installer_args . extend_from_slice ( & args ) ;
self
}
pub fn clear_installer_args ( mut self ) -> Self {
self . installer_args . clear ( ) ;
self
self
}
}
pub fn build ( self ) -> Result < Updater > {
pub fn build ( self ) -> Result < Updater > {
let endpoints = self
let endpoints = self
. endpoints
. endpoints
. unwrap_or_else ( | | self . config . endpoints . into_iter ( ) . map ( | e | e . 0 ) . collect ( ) ) ;
. unwrap_or_else ( | | self . config . endpoints . i ter( ) . map ( | e | e . 0. clone ( ) ) . collect ( ) ) ;
if endpoints . is_empty ( ) {
if endpoints . is_empty ( ) {
return Err ( Error ::EmptyEndpoints ) ;
return Err ( Error ::EmptyEndpoints ) ;
@ -207,13 +227,13 @@ impl UpdaterBuilder {
} ;
} ;
Ok ( Updater {
Ok ( Updater {
config : self . updater_ config,
config : self . config,
current_version : self . current_version ,
current_version : self . current_version ,
version_comparator : self . version_comparator ,
version_comparator : self . version_comparator ,
timeout : self . timeout ,
timeout : self . timeout ,
proxy : self . proxy ,
proxy : self . proxy ,
endpoints ,
endpoints ,
installer_args : self . installer_args .unwrap_or ( self . config . installer_args ) ,
installer_args : self . installer_args ,
arch ,
arch ,
target ,
target ,
json_target ,
json_target ,
@ -224,14 +244,14 @@ impl UpdaterBuilder {
}
}
pub struct Updater {
pub struct Updater {
config : Updater Config,
config : Config,
current_version : Version ,
current_version : Version ,
version_comparator : Option < Box < dyn Fn ( Version , RemoteRelease ) -> bool + Send + Sync > > ,
version_comparator : Option < Box < dyn Fn ( Version , RemoteRelease ) -> bool + Send + Sync > > ,
timeout : Option < Duration > ,
timeout : Option < Duration > ,
proxy : Option < Url > ,
proxy : Option < Url > ,
endpoints : Vec < Url > ,
endpoints : Vec < Url > ,
#[ allow(dead_code) ]
#[ allow(dead_code) ]
installer_args : Vec < String> ,
installer_args : Vec < Os String> ,
arch : & ' static str ,
arch : & ' static str ,
// The `{{target}}` variable we replace in the endpoint
// The `{{target}}` variable we replace in the endpoint
target : String ,
target : String ,
@ -336,8 +356,8 @@ impl Updater {
let update = if should_update {
let update = if should_update {
Some ( Update {
Some ( Update {
current_version : self . current_version . to_string ( ) ,
config : self . config . clone ( ) ,
config : self . config . clone ( ) ,
current_version : self . current_version . to_string ( ) ,
target : self . target . clone ( ) ,
target : self . target . clone ( ) ,
extract_path : self . extract_path . clone ( ) ,
extract_path : self . extract_path . clone ( ) ,
installer_args : self . installer_args . clone ( ) ,
installer_args : self . installer_args . clone ( ) ,
@ -360,7 +380,7 @@ impl Updater {
#[ derive(Debug, Clone) ]
#[ derive(Debug, Clone) ]
pub struct Update {
pub struct Update {
config : Updater Config,
config : Config,
/// Update description
/// Update description
pub body : Option < String > ,
pub body : Option < String > ,
/// Version used to check for update
/// Version used to check for update
@ -375,7 +395,7 @@ pub struct Update {
#[ allow(unused) ]
#[ allow(unused) ]
extract_path : PathBuf ,
extract_path : PathBuf ,
#[ allow(unused) ]
#[ allow(unused) ]
installer_args : Vec < String> ,
installer_args : Vec < Os String> ,
/// Download URL announced
/// Download URL announced
pub download_url : Url ,
pub download_url : Url ,
/// Signature announced
/// Signature announced
@ -495,7 +515,7 @@ impl Update {
// Update server can provide a custom EXE (installer) who can run any task.
// Update server can provide a custom EXE (installer) who can run any task.
#[ cfg(windows) ]
#[ cfg(windows) ]
fn install_inner ( & self , bytes : Vec < u8 > ) -> Result < ( ) > {
fn install_inner ( & self , bytes : Vec < u8 > ) -> Result < ( ) > {
use std ::{ f fi::OsStr , f s, process ::Command } ;
use std ::{ f s, process ::Command } ;
// FIXME: We need to create a memory buffer with the MSI and then run it.
// FIXME: We need to create a memory buffer with the MSI and then run it.
// (instead of extracting the MSI to a temp path)
// (instead of extracting the MSI to a temp path)
@ -535,12 +555,21 @@ impl Update {
installer_path . push ( "\"" ) ;
installer_path . push ( "\"" ) ;
let installer_args = [
let installer_args = [
self . config . windows . install_mode . nsis_args ( ) ,
self . config
self . installer_args
. windows
. as_ref ( )
. map ( | w | {
w . install_mode
. nsis_args ( )
. iter ( )
. iter ( )
. map ( AsRef ::as_ref )
. map ( | a | OsStr ::new ( a ) )
. collect ::< Vec < _ > > ( )
. collect ::< Vec < _ > > ( )
. as_slice ( ) ,
} )
. unwrap_or_default ( ) ,
self . installer_args
. iter ( )
. map ( | a | a . as_os_str ( ) )
. collect ::< Vec < _ > > ( ) ,
]
]
. concat ( ) ;
. concat ( ) ;
@ -552,7 +581,8 @@ impl Update {
. arg ( installer_path ) ;
. arg ( installer_path ) ;
if ! installer_args . is_empty ( ) {
if ! installer_args . is_empty ( ) {
cmd . arg ( "-ArgumentList" ) . arg ( installer_args . join ( ", " ) ) ;
cmd . arg ( "-ArgumentList" )
. arg ( installer_args . join ( OsStr ::new ( ", " ) ) ) ;
}
}
cmd . spawn ( ) . expect ( "installer failed to start" ) ;
cmd . spawn ( ) . expect ( "installer failed to start" ) ;
@ -570,12 +600,21 @@ impl Update {
msi_path . push ( "\"\"\"" ) ;
msi_path . push ( "\"\"\"" ) ;
let installer_args = [
let installer_args = [
self . config . windows . install_mode . msiexec_args ( ) ,
self . config
self . installer_args
. windows
. as_ref ( )
. map ( | w | {
w . install_mode
. msiexec_args ( )
. iter ( )
. iter ( )
. map ( AsRef ::as_ref )
. map ( | a | OsStr ::new ( a ) )
. collect ::< Vec < _ > > ( )
. collect ::< Vec < _ > > ( )
. as_slice ( ) ,
} )
. unwrap_or_default ( ) ,
self . installer_args
. iter ( )
. map ( | a | a . as_os_str ( ) )
. collect ::< Vec < _ > > ( ) ,
]
]
. concat ( ) ;
. concat ( ) ;
@ -591,7 +630,10 @@ impl Update {
] )
] )
. arg ( "/i," )
. arg ( "/i," )
. arg ( & msi_path )
. arg ( & msi_path )
. arg ( format! ( ", {}, /promptrestart;" , installer_args . join ( ", " ) ) )
. arg ( format! (
", {}, /promptrestart;" ,
installer_args . join ( OsStr ::new ( ", " ) ) . to_string_lossy ( )
) )
. arg ( "Start-Process" )
. arg ( "Start-Process" )
. arg ( current_exe_arg )
. arg ( current_exe_arg )
. spawn ( ) ;
. spawn ( ) ;
@ -636,10 +678,7 @@ impl Update {
) ) ]
) ) ]
fn install_inner ( & self , bytes : Vec < u8 > ) -> Result < ( ) > {
fn install_inner ( & self , bytes : Vec < u8 > ) -> Result < ( ) > {
use flate2 ::read ::GzDecoder ;
use flate2 ::read ::GzDecoder ;
use std ::{
use std ::os ::unix ::fs ::{ MetadataExt , PermissionsExt } ;
ffi ::OsStr ,
os ::unix ::fs ::{ MetadataExt , PermissionsExt } ,
} ;
let archive = Cursor ::new ( bytes ) ;
let archive = Cursor ::new ( bytes ) ;
let extract_path_metadata = self . extract_path . metadata ( ) ? ;
let extract_path_metadata = self . extract_path . metadata ( ) ? ;