Skip to content

Commit 673dbde

Browse files
committed
Fix installer existing-install flow for GUI and keep mode
1 parent c51e1b9 commit 673dbde

4 files changed

Lines changed: 187 additions & 70 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ The installer places:
9090
If an existing DevStack installation is found, the installer will ask whether to remove it before installing:
9191

9292
- `remove` existing files and continue installation
93-
- `keep` existing installation and cancel install
93+
- `keep` keep the current installation unchanged and complete without replacing it
9494
- `abort` install
9595

9696
For non-interactive installs in CI or scripts, set:
@@ -99,7 +99,7 @@ For non-interactive installs in CI or scripts, set:
9999
export DEVSTACK_INSTALL_EXISTING_POLICY=remove
100100
```
101101

102-
to replace existing files automatically, or leave it unset to keep existing installation and cancel the install.
102+
to replace existing files automatically. Set it to `keep` to preserve the current installation without replacing it.
103103

104104
If installation succeeds, `dx` is available at `/usr/local/bin/dx` and should run immediately in a new shell.
105105
If an existing shell still does not resolve `dx` (rare `zsh` command cache case), reopen the shell or run:

Scripts/pkg-scripts/postinstall

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,62 @@
11
#!/bin/sh
22
set -eu
33

4-
if [ ! -x /usr/local/bin/dx ]; then
4+
DEVSTACK_APP="/Applications/DevStackMenu.app"
5+
IMPORTER_APP="/Applications/Import Compose To DX.app"
6+
DX_BINARY="/usr/local/bin/dx"
7+
STATE_DIR="/private/tmp/devstackmenu-installer"
8+
POLICY_FILE="$STATE_DIR/policy"
9+
BACKUP_DIR="$STATE_DIR/backup"
10+
11+
cleanup_state() {
12+
rm -rf "$STATE_DIR"
13+
}
14+
15+
remove_path_if_present() {
16+
target_path="$1"
17+
18+
if [ -d "$target_path" ]; then
19+
rm -rf "$target_path"
20+
elif [ -e "$target_path" ]; then
21+
rm -f "$target_path"
22+
fi
23+
}
24+
25+
restore_or_remove() {
26+
target_path="$1"
27+
backup_path="$2"
28+
29+
remove_path_if_present "$target_path"
30+
if [ -e "$backup_path" ]; then
31+
/usr/bin/ditto "$backup_path" "$target_path"
32+
fi
33+
}
34+
35+
policy="install"
36+
if [ -f "$POLICY_FILE" ]; then
37+
policy="$(cat "$POLICY_FILE")"
38+
fi
39+
40+
if [ "$policy" = "keep" ]; then
41+
restore_or_remove "$DEVSTACK_APP" "$BACKUP_DIR/DevStackMenu.app"
42+
restore_or_remove "$IMPORTER_APP" "$BACKUP_DIR/Import Compose To DX.app"
43+
restore_or_remove "$DX_BINARY" "$BACKUP_DIR/dx"
44+
cleanup_state
45+
echo "Existing DevStack installation kept unchanged."
46+
exit 0
47+
fi
48+
49+
cleanup_state
50+
51+
if [ ! -x "$DX_BINARY" ]; then
552
echo "Installation failed: /usr/local/bin/dx is not installed" >&2
653
exit 1
754
fi
855

9-
DX_BIN="/usr/local/bin/dx"
1056
DX_STATUS_OUTPUT="$(mktemp)"
1157
DX_EXIT_CODE=0
1258

13-
if ! "$DX_BIN" >"$DX_STATUS_OUTPUT" 2>&1; then
59+
if ! "$DX_BINARY" >"$DX_STATUS_OUTPUT" 2>&1; then
1460
DX_EXIT_CODE=$?
1561
fi
1662

@@ -24,7 +70,7 @@ fi
2470

2571
rm -f "$DX_STATUS_OUTPUT"
2672

27-
if ! "$DX_BIN" status >/dev/null 2>&1; then
73+
if ! "$DX_BINARY" status >/dev/null 2>&1; then
2874
echo "Installation failed: /usr/local/bin/dx is not executable" >&2
2975
exit 1
3076
fi

Scripts/pkg-scripts/preinstall

Lines changed: 133 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -4,93 +4,164 @@ set -eu
44
DEVSTACK_APP="/Applications/DevStackMenu.app"
55
IMPORTER_APP="/Applications/Import Compose To DX.app"
66
DX_BINARY="/usr/local/bin/dx"
7+
STATE_DIR="/private/tmp/devstackmenu-installer"
8+
POLICY_FILE="$STATE_DIR/policy"
9+
BACKUP_DIR="$STATE_DIR/backup"
710

8-
HAVE_EXISTING=0
9-
[ -d "$DEVSTACK_APP" ] && HAVE_EXISTING=1
10-
[ -d "$IMPORTER_APP" ] && HAVE_EXISTING=1
11-
[ -e "$DX_BINARY" ] && HAVE_EXISTING=1
11+
ensure_state_dir() {
12+
rm -rf "$STATE_DIR"
13+
mkdir -p "$BACKUP_DIR"
14+
}
1215

13-
if [ "$HAVE_EXISTING" -eq 0 ]; then
14-
exit 0
15-
fi
16-
17-
DEVSTACK_VERSION="unknown"
18-
if [ -f "$DEVSTACK_APP/Contents/Info.plist" ]; then
19-
DEVSTACK_VERSION="$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$DEVSTACK_APP/Contents/Info.plist" 2>/dev/null || true)"
20-
DEVSTACK_VERSION="${DEVSTACK_VERSION:-unknown}"
21-
fi
22-
23-
DX_VERSION="unknown"
24-
if [ -f "$DX_BINARY" ]; then
25-
if DX_HELPER_OUTPUT="$("$DX_BINARY" --version 2>/dev/null || true)"; then
26-
DX_VERSION="$DX_HELPER_OUTPUT"
16+
path_present() {
17+
if [ -e "$1" ]; then
18+
printf 'yes'
2719
else
28-
DX_VERSION="installed"
20+
printf 'no'
2921
fi
30-
fi
31-
32-
echo "Existing DevStack installation detected."
33-
echo " - $DEVSTACK_APP (version: $DEVSTACK_VERSION)"
34-
echo " - $IMPORTER_APP (installed: $([ -d \"$IMPORTER_APP\" ] && echo yes || echo no))"
35-
echo " - $DX_BINARY (installed: $([ -e \"$DX_BINARY\" ] && echo yes || echo no), version: $DX_VERSION)"
36-
echo
37-
38-
if [ "${DEVSTACK_INSTALL_EXISTING_POLICY:-}" = "remove" ]; then
39-
CHOICE="remove"
40-
elif [ "${DEVSTACK_INSTALL_EXISTING_POLICY:-}" = "keep" ] || [ "${DEVSTACK_INSTALL_EXISTING_POLICY:-}" = "skip" ]; then
41-
CHOICE="keep"
42-
elif [ "${DEVSTACK_INSTALL_EXISTING_POLICY:-}" = "abort" ]; then
43-
CHOICE="abort"
44-
else
45-
CHOICE=""
46-
fi
22+
}
4723

48-
if [ -z "$CHOICE" ] && [ ! -t 0 ]; then
49-
echo "Non-interactive install: keeping existing installation and cancelling package install."
50-
echo "Re-run with DEVSTACK_INSTALL_EXISTING_POLICY=remove to replace existing installation."
51-
exit 1
52-
fi
53-
54-
if [ -z "$CHOICE" ] && [ -r /dev/tty ]; then
24+
prompt_in_tty() {
5525
while true; do
56-
printf "Choose action: [r] Remove existing and install / [k] Keep existing unchanged (cancel install) / [a] Abort: "
57-
if ! IFS= read -r CHOICE </dev/tty; then
58-
echo "Could not read decision. Cancelling install." >&2
59-
exit 1
26+
printf "Existing DevStack installation found. Choose action: [r] Replace / [k] Keep unchanged / [a] Abort: "
27+
if ! IFS= read -r choice; then
28+
printf 'abort\n'
29+
return
6030
fi
61-
case "$CHOICE" in
31+
32+
case "$choice" in
6233
r|R)
63-
CHOICE="remove"
64-
break
34+
printf 'remove\n'
35+
return
6536
;;
6637
k|K)
67-
CHOICE="keep"
68-
break
38+
printf 'keep\n'
39+
return
6940
;;
7041
a|A)
71-
CHOICE="abort"
72-
break
73-
;;
74-
*)
75-
echo "Invalid choice: $CHOICE"
42+
printf 'abort\n'
43+
return
7644
;;
7745
esac
7846
done
47+
}
48+
49+
prompt_in_gui() {
50+
console_user="$(stat -f %Su /dev/console 2>/dev/null || printf '%s' root)"
51+
if [ -z "$console_user" ] || [ "$console_user" = "root" ]; then
52+
return 1
53+
fi
54+
55+
console_uid="$(id -u "$console_user" 2>/dev/null || true)"
56+
if [ -z "$console_uid" ]; then
57+
return 1
58+
fi
59+
60+
result="$(
61+
/bin/launchctl asuser "$console_uid" /usr/bin/osascript \
62+
-e 'button returned of (display dialog "Existing DevStack installation found.\n\nReplace it with this package or keep the current installation unchanged?" with title "DevStackMenu Installer" buttons {"Abort", "Keep", "Replace"} default button "Replace" cancel button "Abort" with icon caution)' \
63+
2>/dev/null || true
64+
)"
65+
66+
case "$result" in
67+
Replace)
68+
printf 'remove\n'
69+
return
70+
;;
71+
Keep)
72+
printf 'keep\n'
73+
return
74+
;;
75+
*)
76+
printf 'abort\n'
77+
return
78+
;;
79+
esac
80+
}
81+
82+
resolve_choice() {
83+
case "${DEVSTACK_INSTALL_EXISTING_POLICY:-}" in
84+
remove)
85+
printf 'remove\n'
86+
return
87+
;;
88+
keep|skip)
89+
printf 'keep\n'
90+
return
91+
;;
92+
abort)
93+
printf 'abort\n'
94+
return
95+
;;
96+
"")
97+
;;
98+
*)
99+
echo "Invalid DEVSTACK_INSTALL_EXISTING_POLICY: ${DEVSTACK_INSTALL_EXISTING_POLICY}" >&2
100+
printf 'abort\n'
101+
return
102+
;;
103+
esac
104+
105+
if [ -t 0 ] && [ -t 1 ]; then
106+
prompt_in_tty
107+
return
108+
fi
109+
110+
if prompt_in_gui; then
111+
return
112+
fi
113+
114+
printf 'abort\n'
115+
}
116+
117+
backup_path_if_present() {
118+
source_path="$1"
119+
backup_name="$2"
120+
121+
if [ -e "$source_path" ]; then
122+
/usr/bin/ditto "$source_path" "$BACKUP_DIR/$backup_name"
123+
fi
124+
}
125+
126+
has_existing_installation=0
127+
[ -e "$DEVSTACK_APP" ] && has_existing_installation=1
128+
[ -e "$IMPORTER_APP" ] && has_existing_installation=1
129+
[ -e "$DX_BINARY" ] && has_existing_installation=1
130+
131+
ensure_state_dir
132+
133+
if [ "$has_existing_installation" -eq 0 ]; then
134+
printf 'install\n' > "$POLICY_FILE"
135+
exit 0
79136
fi
80137

81-
case "$CHOICE" in
138+
echo "Existing DevStack installation detected."
139+
echo " - $DEVSTACK_APP: $(path_present "$DEVSTACK_APP")"
140+
echo " - $IMPORTER_APP: $(path_present "$IMPORTER_APP")"
141+
echo " - $DX_BINARY: $(path_present "$DX_BINARY")"
142+
143+
choice="$(resolve_choice)"
144+
printf '%s\n' "$choice" > "$POLICY_FILE"
145+
146+
case "$choice" in
82147
remove)
83148
[ -d "$DEVSTACK_APP" ] && rm -rf "$DEVSTACK_APP"
84149
[ -d "$IMPORTER_APP" ] && rm -rf "$IMPORTER_APP"
85150
[ -e "$DX_BINARY" ] && rm -f "$DX_BINARY"
86-
echo "Existing DevStack files removed. Continuing with installation."
151+
echo "Replacing existing DevStack installation."
152+
;;
153+
keep)
154+
backup_path_if_present "$DEVSTACK_APP" "DevStackMenu.app"
155+
backup_path_if_present "$IMPORTER_APP" "Import Compose To DX.app"
156+
backup_path_if_present "$DX_BINARY" "dx"
157+
echo "Keeping existing DevStack installation unchanged."
87158
;;
88-
keep|abort|"")
89-
echo "Keeping existing installation. Cancelling package installation."
159+
abort)
160+
echo "Installation aborted by user."
90161
exit 1
91162
;;
92163
*)
93-
echo "Invalid policy '$CHOICE'. Cancelling installation."
164+
echo "Unknown install policy: $choice" >&2
94165
exit 1
95166
;;
96167
esac

Scripts/release-smoke-install.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ fi
5151

5252
printf 'Installing package (requires sudo)...\n'
5353
if [ "$(id -u)" -eq 0 ]; then
54-
installer -pkg "$PKG_PATH" -target / | tee "$TMP_LOG"
54+
DEVSTACK_INSTALL_EXISTING_POLICY=remove installer -pkg "$PKG_PATH" -target / | tee "$TMP_LOG"
5555
else
56-
sudo installer -pkg "$PKG_PATH" -target / | tee "$TMP_LOG"
56+
sudo env DEVSTACK_INSTALL_EXISTING_POLICY=remove installer -pkg "$PKG_PATH" -target / | tee "$TMP_LOG"
5757
fi
5858

5959
printf 'Verifying installed artifacts...\n'

0 commit comments

Comments
 (0)