Add quit and relaunch logic to macOS FMAs (#37670)
This pull request enhances the macOS app installation process by improving how running applications are handled during install and update, and also updates the metadata and scripts for Docker Desktop. The main improvements are the introduction of quit/relaunch logic for pkg-based FMAs, and the renaming and updating of Docker Desktop’s identifiers and scripts. **App install/relaunch improvements:** * Added new shell functions `quit_and_track_application` and `relaunch_application` to the generated install scripts. These functions ensure that if an app (or pkg) is running before installation, it is quit and then automatically relaunched after installation, preserving user state. The logic tracks whether the app was running via an environment variable. [[1]](diffhunk://#diff-a9df2db484fcbb560d62c43f94c4bcc2d26dcf68066c9e7cc2bffad6f124ce97L22-R41) [[2]](diffhunk://#diff-a9df2db484fcbb560d62c43f94c4bcc2d26dcf68066c9e7cc2bffad6f124ce97R53-R59) [[3]](diffhunk://#diff-a9df2db484fcbb560d62c43f94c4bcc2d26dcf68066c9e7cc2bffad6f124ce97R72-R73) [[4]](diffhunk://#diff-a9df2db484fcbb560d62c43f94c4bcc2d26dcf68066c9e7cc2bffad6f124ce97R571-R648) * Removed the previous simpler `quit_application` logic from the install script generation, as the new functions supersede it. **Docker Desktop metadata and script updates:** * Renamed the Docker Desktop input and updated its `slug` and `unique_identifier` to match the new bundle identifier (`com.electron.dockerdesktop`), reflecting the current packaging. * Updated the output app metadata in `apps.json` to use the new slug and unique identifier for Docker Desktop. * Added a new output file for Docker Desktop (`docker-desktop/darwin.json`) with the updated install and uninstall scripts, including the new quit/relaunch logic and references.
This commit is contained in:
@@ -19,16 +19,26 @@ func installScriptForApp(app inputApp, cask *brewCask) (string, error) {
|
||||
|
||||
sb.Extract(app.InstallerFormat)
|
||||
|
||||
var includeQuitFunc bool
|
||||
// Add quit/relaunch functions if we have App or Pkg artifacts
|
||||
var needsQuitRelaunch bool
|
||||
for _, artifact := range cask.Artifacts {
|
||||
if len(artifact.App) > 0 || len(artifact.Pkg) > 0 {
|
||||
needsQuitRelaunch = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if needsQuitRelaunch {
|
||||
sb.AddFunction("quit_and_track_application", quitAndTrackApplicationFunc)
|
||||
sb.AddFunction("relaunch_application", relaunchApplicationFunc)
|
||||
}
|
||||
|
||||
for _, artifact := range cask.Artifacts {
|
||||
switch {
|
||||
case len(artifact.App) > 0:
|
||||
sb.Write("# copy to the applications folder")
|
||||
sb.Writef("quit_application '%s'", app.UniqueIdentifier)
|
||||
if cask.Token == "docker" {
|
||||
sb.Writef("quit_application 'com.electron.dockerdesktop'")
|
||||
}
|
||||
includeQuitFunc = true
|
||||
// Quit the app before installing if it's running, and track state for relaunch
|
||||
sb.Writef("quit_and_track_application '%s'", app.UniqueIdentifier)
|
||||
for _, appItem := range artifact.App {
|
||||
// Only process string values (skip objects with target, those are handled by custom scripts)
|
||||
if appItem.String == "" {
|
||||
@@ -40,9 +50,13 @@ func installScriptForApp(app inputApp, cask *brewCask) (string, error) {
|
||||
fi`, appPath)
|
||||
sb.Copy(appPath, "$APPDIR")
|
||||
}
|
||||
// Relaunch the app if it was running before installation
|
||||
sb.Writef("relaunch_application '%s'", app.UniqueIdentifier)
|
||||
|
||||
case len(artifact.Pkg) > 0:
|
||||
sb.Write("# install pkg files")
|
||||
// Quit the app before installing if it's running, and track state for relaunch
|
||||
sb.Writef("quit_and_track_application '%s'", app.UniqueIdentifier)
|
||||
switch len(artifact.Pkg) {
|
||||
case 1:
|
||||
if err := sb.InstallPkg(artifact.Pkg[0].String); err != nil {
|
||||
@@ -55,6 +69,8 @@ fi`, appPath)
|
||||
default:
|
||||
return "", fmt.Errorf("application %s has unknown directive format for pkg", app.Token)
|
||||
}
|
||||
// Relaunch the app if it was running before installation
|
||||
sb.Writef("relaunch_application '%s'", app.UniqueIdentifier)
|
||||
|
||||
case len(artifact.Binary) > 0:
|
||||
if len(artifact.Binary) == 2 {
|
||||
@@ -69,10 +85,6 @@ fi`, appPath)
|
||||
}
|
||||
}
|
||||
|
||||
if includeQuitFunc {
|
||||
sb.AddFunction("quit_application", quitApplicationFunc)
|
||||
}
|
||||
|
||||
return sb.String(), nil
|
||||
}
|
||||
|
||||
@@ -556,6 +568,84 @@ const quitApplicationFunc = `quit_application() {
|
||||
}
|
||||
`
|
||||
|
||||
// quitAndTrackApplicationFunc quits a running application and tracks whether it was running
|
||||
// so it can be relaunched after installation. Sets APP_WAS_RUNNING_<bundle_id> environment variable.
|
||||
const quitAndTrackApplicationFunc = `quit_and_track_application() {
|
||||
local bundle_id="$1"
|
||||
local var_name="APP_WAS_RUNNING_$(echo "$bundle_id" | tr '.-' '__')"
|
||||
local timeout_duration=10
|
||||
|
||||
# check if the application is running
|
||||
if ! osascript -e "application id \"$bundle_id\" is running" 2>/dev/null; then
|
||||
eval "export $var_name=0"
|
||||
return
|
||||
fi
|
||||
|
||||
local console_user
|
||||
console_user=$(stat -f "%Su" /dev/console)
|
||||
if [[ $EUID -eq 0 && "$console_user" == "root" ]]; then
|
||||
echo "Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'."
|
||||
eval "export $var_name=0"
|
||||
return
|
||||
fi
|
||||
|
||||
# App was running, mark it for relaunch
|
||||
eval "export $var_name=1"
|
||||
echo "Application '$bundle_id' was running; will relaunch after installation."
|
||||
|
||||
echo "Quitting application '$bundle_id'..."
|
||||
|
||||
# try to quit the application within the timeout period
|
||||
local quit_success=false
|
||||
SECONDS=0
|
||||
while (( SECONDS < timeout_duration )); do
|
||||
if osascript -e "tell application id \"$bundle_id\" to quit" >/dev/null 2>&1; then
|
||||
if ! pgrep -f "$bundle_id" >/dev/null 2>&1; then
|
||||
echo "Application '$bundle_id' quit successfully."
|
||||
quit_success=true
|
||||
break
|
||||
fi
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if [[ "$quit_success" = false ]]; then
|
||||
echo "Application '$bundle_id' did not quit."
|
||||
fi
|
||||
}
|
||||
`
|
||||
|
||||
// relaunchApplicationFunc relaunches an application if it was running before installation.
|
||||
// Checks the APP_WAS_RUNNING_<bundle_id> environment variable set by quitAndTrackApplicationFunc.
|
||||
const relaunchApplicationFunc = `relaunch_application() {
|
||||
local bundle_id="$1"
|
||||
local var_name="APP_WAS_RUNNING_$(echo "$bundle_id" | tr '.-' '__')"
|
||||
local was_running
|
||||
|
||||
# Check if the app was running before installation
|
||||
eval "was_running=\$$var_name"
|
||||
if [[ "$was_running" != "1" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
local console_user
|
||||
console_user=$(stat -f "%Su" /dev/console)
|
||||
if [[ $EUID -eq 0 && "$console_user" == "root" ]]; then
|
||||
echo "Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'."
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Relaunching application '$bundle_id'..."
|
||||
|
||||
# Try to launch the application
|
||||
if osascript -e "tell application id \"$bundle_id\" to activate" >/dev/null 2>&1; then
|
||||
echo "Application '$bundle_id' relaunched successfully."
|
||||
else
|
||||
echo "Failed to relaunch application '$bundle_id'."
|
||||
fi
|
||||
}
|
||||
`
|
||||
|
||||
const trashFunc = `trash() {
|
||||
local logged_in_user="$1"
|
||||
local target_file="$2"
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Docker Desktop",
|
||||
"slug": "docker/darwin",
|
||||
"unique_identifier": "com.docker.docker",
|
||||
"slug": "docker-desktop/darwin",
|
||||
"unique_identifier": "com.electron.dockerdesktop",
|
||||
"token": "docker-desktop",
|
||||
"installer_format": "dmg",
|
||||
"default_categories": ["Developer tools"]
|
||||
@@ -570,9 +570,9 @@
|
||||
},
|
||||
{
|
||||
"name": "Docker Desktop",
|
||||
"slug": "docker/darwin",
|
||||
"slug": "docker-desktop/darwin",
|
||||
"platform": "darwin",
|
||||
"unique_identifier": "com.docker.docker",
|
||||
"unique_identifier": "com.electron.dockerdesktop",
|
||||
"description": "Docker Desktop provides a seamless environment for building, sharing, and running containerized applications and microservices."
|
||||
},
|
||||
{
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 6.1 KiB |
Reference in New Issue
Block a user