From 36aa3705497265ea121d942e7fe5648554138511 Mon Sep 17 00:00:00 2001 From: Harrison Ravazzolo <38767391+harrisonravazzolo@users.noreply.github.com> Date: Sun, 7 Jun 2026 18:28:08 -0700 Subject: [PATCH] Add Beekeeper Studio as a macOS FMA (#47046) --- .../inputs/homebrew/beekeeper-studio.json | 8 +++++++ ee/maintained-apps/outputs/apps.json | 7 ++++++ .../outputs/beekeeper-studio/darwin.json | 22 ++++++++++++++++++ .../components/icons/BeekeeperStudio.tsx | 14 +++++++++++ .../SoftwarePage/components/icons/index.ts | 2 ++ .../app-icon-beekeeper-studio-60x60@2x.png | Bin 0 -> 6661 bytes 6 files changed, 53 insertions(+) create mode 100644 ee/maintained-apps/inputs/homebrew/beekeeper-studio.json create mode 100644 ee/maintained-apps/outputs/beekeeper-studio/darwin.json create mode 100644 frontend/pages/SoftwarePage/components/icons/BeekeeperStudio.tsx create mode 100644 website/assets/images/app-icon-beekeeper-studio-60x60@2x.png diff --git a/ee/maintained-apps/inputs/homebrew/beekeeper-studio.json b/ee/maintained-apps/inputs/homebrew/beekeeper-studio.json new file mode 100644 index 0000000000..5244ccd2a5 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/beekeeper-studio.json @@ -0,0 +1,8 @@ +{ + "name": "Beekeeper Studio", + "unique_identifier": "io.beekeeperstudio.desktop", + "token": "beekeeper-studio", + "installer_format": "dmg", + "slug": "beekeeper-studio/darwin", + "default_categories": ["Developer tools"] +} diff --git a/ee/maintained-apps/outputs/apps.json b/ee/maintained-apps/outputs/apps.json index 8ef1471578..593e8e50b0 100644 --- a/ee/maintained-apps/outputs/apps.json +++ b/ee/maintained-apps/outputs/apps.json @@ -421,6 +421,13 @@ "unique_identifier": "com.barebones.bbedit", "description": "BBEdit is a text, code, and markup editor." }, + { + "name": "Beekeeper Studio", + "slug": "beekeeper-studio/darwin", + "platform": "darwin", + "unique_identifier": "io.beekeeperstudio.desktop", + "description": "Beekeeper Studio is a cross platform SQL editor and database management app." + }, { "name": "BetterDisplay", "slug": "betterdisplay/darwin", diff --git a/ee/maintained-apps/outputs/beekeeper-studio/darwin.json b/ee/maintained-apps/outputs/beekeeper-studio/darwin.json new file mode 100644 index 0000000000..1ffc60706f --- /dev/null +++ b/ee/maintained-apps/outputs/beekeeper-studio/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "5.8.1", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'io.beekeeperstudio.desktop';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'io.beekeeperstudio.desktop' AND version_compare(bundle_short_version, '5.8.1') < 0);" + }, + "installer_url": "https://github.com/beekeeper-studio/beekeeper-studio/releases/download/v5.8.1/Beekeeper-Studio-5.8.1-arm64.dmg", + "install_script_ref": "8f0b1e9d", + "uninstall_script_ref": "eaf45799", + "sha256": "7d4a9d24336b5a1d29b3f33ca16b71f91d6b9bb11c3e116f9d4c9e23b57b6e77", + "default_categories": [ + "Developer tools" + ] + } + ], + "refs": { + "8f0b1e9d": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'io.beekeeperstudio.desktop'\nif [ -d \"$APPDIR/Beekeeper Studio.app\" ]; then\n\tsudo mv \"$APPDIR/Beekeeper Studio.app\" \"$TMPDIR/Beekeeper Studio.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Beekeeper Studio.app\" \"$APPDIR\"\nrelaunch_application 'io.beekeeperstudio.desktop'\n", + "eaf45799": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Beekeeper Studio.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/beekeeper-studio'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Caches/beekeeper-studio-updater'\ntrash $LOGGED_IN_USER '~/Library/Caches/io.beekeeperstudio.desktop'\ntrash $LOGGED_IN_USER '~/Library/Caches/io.beekeeperstudio.desktop.ShipIt'\ntrash $LOGGED_IN_USER '~/Library/Preferences/ByHost/io.beekeeperstudio.desktop.ShipIt.*.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/io.beekeeperstudio.desktop.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/io.beekeeperstudio.desktop.savedState'\n" + } +} diff --git a/frontend/pages/SoftwarePage/components/icons/BeekeeperStudio.tsx b/frontend/pages/SoftwarePage/components/icons/BeekeeperStudio.tsx new file mode 100644 index 0000000000..b977422de7 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/BeekeeperStudio.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const BeekeeperStudio = (props: SVGProps) => ( + + + +); +export default BeekeeperStudio; diff --git a/frontend/pages/SoftwarePage/components/icons/index.ts b/frontend/pages/SoftwarePage/components/icons/index.ts index 502fa1d780..894ac3459e 100644 --- a/frontend/pages/SoftwarePage/components/icons/index.ts +++ b/frontend/pages/SoftwarePage/components/icons/index.ts @@ -16,6 +16,7 @@ import Antigravity from "./Antigravity"; import AzulZulu25Jdk from "./AzulZulu25Jdk"; import AzulZulu25Jre from "./AzulZulu25Jre"; import Backblaze from "./Backblaze"; +import BeekeeperStudio from "./BeekeeperStudio"; import BetterDisplay from "./BetterDisplay"; import Bluej from "./Bluej"; import BurpSuiteCommunity from "./BurpSuiteCommunity"; @@ -364,6 +365,7 @@ export const SOFTWARE_NAME_TO_ICON_MAP = { backblaze: Backblaze, balenaetcher: BalenaEtcher, bbedit: BBEdit, + "beekeeper studio": BeekeeperStudio, betterdisplay: BetterDisplay, "beyond compare": BeyondCompare, bitwarden: Bitwarden, diff --git a/website/assets/images/app-icon-beekeeper-studio-60x60@2x.png b/website/assets/images/app-icon-beekeeper-studio-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..3d330951f02ead557a19ffecb73736474d2abb9d GIT binary patch literal 6661 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 De~%zD literal 0 HcmV?d00001