2626define ( function ( require , exports , module ) {
2727 const AppInit = require ( "utils/AppInit" ) ,
2828 Metrics = require ( "utils/Metrics" ) ,
29+ FileSystem = require ( "filesystem/FileSystem" ) ,
2930 Commands = require ( "command/Commands" ) ,
3031 CommandManager = require ( "command/CommandManager" ) ,
3132 Menus = require ( "command/Menus" ) ,
@@ -334,13 +335,56 @@ define(function (require, exports, module) {
334335 return null ;
335336 }
336337
338+ async function _extractMacInstaller ( ) {
339+ // todo delete .app files already in the install folder
340+ const appdataDir = window . _tauriBootVars . appLocalDir ;
341+ let extractPlatformPath = path . join ( appdataDir , 'installer' , "extracted" ) ;
342+ // extract the .app file
343+ const extractCommand = new window . __TAURI__ . shell
344+ . Command ( `tar-unix` , [ '-xzf' , installerLocation , "-C" , extractPlatformPath ] ) ;
345+ let result = await extractCommand . execute ( ) ;
346+ if ( result . code !== 0 ) {
347+ console . error ( "Could not extract installer at" , installerLocation , "to" , extractPlatformPath ) ;
348+ throw new Error ( "Could not extract installer at " + installerLocation + " to " + extractPlatformPath ) ;
349+ }
350+ // remove the quarantine flag
351+ const removeAttrCommand = new window . __TAURI__ . shell
352+ . Command ( `mac-remove-quarantine` , [ "-rd" , "com.apple.quarantine" , extractPlatformPath ] ) ;
353+ result = await removeAttrCommand . execute ( ) ;
354+ if ( result . code !== 0 ) {
355+ console . error ( "Could not remove quarantine attribute for" , extractPlatformPath , "ignoring..." ) ;
356+ // we can ignore this failure as the user will be asked for permission by os on clicking anyway.
357+ }
358+ // now get the .app path from extracted path
359+ const extractedVirtualPath = window . fs . getTauriVirtualPath ( extractPlatformPath ) ;
360+ let directory = FileSystem . getDirectoryForPath ( extractedVirtualPath ) ;
361+ const { entries} = await directory . getContentsAsync ( ) ;
362+ if ( entries . length !== 1 ) {
363+ throw new Error ( "Could not resolve .app to update from extracted folder" + extractedVirtualPath ) ;
364+ }
365+ installerLocation = window . fs . getTauriPlatformPath ( entries [ 0 ] . fullPath ) ;
366+ }
367+
368+ function _cleanExtractedFolderSilent ( ) {
369+ return new Promise ( resolve => {
370+ const appdataDir = window . _tauriBootVars . appLocalDir ;
371+ let extractPlatformPath = path . join ( appdataDir , 'installer' , "extracted" ) ;
372+ const extractedVirtualPath = window . fs . getTauriVirtualPath ( extractPlatformPath ) ;
373+ let directory = FileSystem . getDirectoryForPath ( extractedVirtualPath ) ;
374+ directory . unlinkAsync ( )
375+ . catch ( console . error )
376+ . finally ( resolve ) ;
377+ } ) ;
378+ }
379+
337380 async function doMacUpdate ( ) {
381+ await _extractMacInstaller ( installerLocation ) ;
338382 const currentAppPath = await getCurrentMacAppPath ( ) ;
339383 if ( ! currentAppPath || ! installerLocation || ! currentAppPath . endsWith ( ".app" ) ||
340384 ! installerLocation . endsWith ( ".app" ) ) {
341385 throw new Error ( "Cannot resolve .app location to copy." ) ;
342386 }
343- const removeCommand = new window . __TAURI__ . shell
387+ let removeCommand = new window . __TAURI__ . shell
344388 . Command ( `recursive-rm-unix` , [ '-r' , currentAppPath ] ) ;
345389 let result = await removeCommand . execute ( ) ;
346390 if ( result . code !== 0 ) {
@@ -353,6 +397,8 @@ define(function (require, exports, module) {
353397 if ( result . code !== 0 ) {
354398 throw new Error ( "Update script exit with non-0 exit code: " + result . code ) ;
355399 }
400+ // now remove the original .app
401+ await _cleanExtractedFolderSilent ( ) ;
356402 }
357403
358404 let installerLocation ;
@@ -413,6 +459,19 @@ define(function (require, exports, module) {
413459 // app updates are only for desktop builds
414460 return ;
415461 }
462+ if ( brackets . platform === "mac" ) {
463+ // in mac, the `update.app.tar.gz` is downloaded, and only extracted on app quit.
464+ // we do this only in mac as the `.app` file is extracted only at app quit and deleted
465+ // and if we see the `extracted file` at app boot, it means the update was broken,and we clear
466+ // the updated folder. if not, the extracted app may be corrupt, or mac will show that app
467+ // too in the finder `open with` section.
468+ // in windows, the `setup.exe.zip` is downloaded and extracted to `setup.exe`. The exe is executed
469+ // only on app quit. so if we do this in windows, the extracted installer.exe will be
470+ // deleted on new widow create and the final update will fail if other windows were opened
471+ // after the installer was downloaded and extracted.
472+ // in Linux, it is an online installer, nothing is downloaded.
473+ _cleanExtractedFolderSilent ( ) ;
474+ }
416475 updaterWindow = window . __TAURI__ . window . WebviewWindow . getByLabel ( TAURI_UPDATER_WINDOW_LABEL ) ;
417476 window . __TAURI__ . event . listen ( "updater-event" , ( receivedEvent ) => {
418477 console . log ( "received Event updater-event" , receivedEvent ) ;
0 commit comments