mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 07:46:12 +03:00
Merge pull request #1126 from mitchellh/sparkle
macOS: Sparkle update framework
This commit is contained in:
48
.github/workflows/release-tip.yml
vendored
48
.github/workflows/release-tip.yml
vendored
@ -48,6 +48,17 @@ jobs:
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
|
||||
# Setup Sparkle
|
||||
- name: Setup Sparkle
|
||||
env:
|
||||
SPARKLE_VERSION: 2.5.1
|
||||
run: |
|
||||
mkdir -p .action/sparkle
|
||||
cd .action/sparkle
|
||||
curl -L https://github.com/sparkle-project/Sparkle/releases/download/${SPARKLE_VERSION}/Sparkle-for-Swift-Package-Manager.zip > sparkle.zip
|
||||
unzip sparkle.zip
|
||||
echo "$(pwd)/bin" >> $GITHUB_PATH
|
||||
|
||||
# Setup our S3 client
|
||||
- name: Setup s3cmd
|
||||
uses: s3-actions/s3cmd@v1.5.0
|
||||
@ -55,7 +66,7 @@ jobs:
|
||||
provider: cloudflare
|
||||
account_id: ${{ secrets.CF_R2_TIP_ACCOUNT_ID }}
|
||||
access_key: ${{ secrets.CF_R2_TIP_AWS_KEY }}
|
||||
secreT_key: ${{ secrets.CF_R2_TIP_SECRET_KEY }}
|
||||
secret_key: ${{ secrets.CF_R2_TIP_SECRET_KEY }}
|
||||
|
||||
# Load Build Number
|
||||
- name: Build Number
|
||||
@ -76,12 +87,18 @@ jobs:
|
||||
|
||||
# We inject the "build number" as simply the number of commits since HEAD.
|
||||
# This will be a monotonically always increasing build number that we use.
|
||||
- name: Inject Build Number
|
||||
- name: Update Info.plist
|
||||
env:
|
||||
SPARKLE_KEY_PUB: ${{ secrets.PROD_MACOS_SPARKLE_KEY_PUB }}
|
||||
run: |
|
||||
# Version Info
|
||||
/usr/libexec/PlistBuddy -c "Set :GhosttyCommit $GHOSTTY_COMMIT" "macos/build/Release/Ghostty.app/Contents/Info.plist"
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $GHOSTTY_BUILD" "macos/build/Release/Ghostty.app/Contents/Info.plist"
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $GHOSTTY_COMMIT" "macos/build/Release/Ghostty.app/Contents/Info.plist"
|
||||
|
||||
# Updater
|
||||
/usr/libexec/PlistBuddy -c "Set :SUPublicEDKey $SPARKLE_KEY_PUB" "macos/build/Release/Ghostty.app/Contents/Info.plist"
|
||||
|
||||
- name: Zip Unsigned App
|
||||
run: nix develop -c sh -c 'cd macos/build/Release && zip -9 -r --symlinks ../../../ghostty-macos-universal-unsigned.zip Ghostty.app'
|
||||
|
||||
@ -115,8 +132,19 @@ jobs:
|
||||
security import certificate.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CI_KEYCHAIN_PWD" build.keychain
|
||||
|
||||
# We finally codesign our app bundle, specifying the Hardened runtime option
|
||||
/usr/bin/codesign --force -s "$MACOS_CERTIFICATE_NAME" --options runtime macos/build/Release/Ghostty.app -v
|
||||
# Codesign Sparkle. Some notes here:
|
||||
# - The XPC services aren't used since we don't sandbox Ghostty,
|
||||
# but since they're part of the build, they still need to be
|
||||
# codesigned.
|
||||
# - The binaries in the "Versions" folders need to NOT be symlinks.
|
||||
/usr/bin/codesign --verbose -f -s "$MACOS_CERTIFICATE_NAME" -o runtime "macos/build/Release/Ghostty.app/Contents/Frameworks/Sparkle.framework/Versions/B/XPCServices/Downloader.xpc"
|
||||
/usr/bin/codesign --verbose -f -s "$MACOS_CERTIFICATE_NAME" -o runtime "macos/build/Release/Ghostty.app/Contents/Frameworks/Sparkle.framework/Versions/B/XPCServices/Installer.xpc"
|
||||
/usr/bin/codesign --verbose -f -s "$MACOS_CERTIFICATE_NAME" -o runtime "macos/build/Release/Ghostty.app/Contents/Frameworks/Sparkle.framework/Versions/B/Autoupdate"
|
||||
/usr/bin/codesign --verbose -f -s "$MACOS_CERTIFICATE_NAME" -o runtime "macos/build/Release/Ghostty.app/Contents/Frameworks/Sparkle.framework/Versions/B/Updater.app"
|
||||
/usr/bin/codesign --verbose -f -s "$MACOS_CERTIFICATE_NAME" -o runtime "macos/build/Release/Ghostty.app/Contents/Frameworks/Sparkle.framework"
|
||||
|
||||
# Codesign the app bundle
|
||||
/usr/bin/codesign --verbose -f -s "$MACOS_CERTIFICATE_NAME" -o runtime macos/build/Release/Ghostty.app
|
||||
|
||||
- name: "Notarize app bundle"
|
||||
env:
|
||||
@ -162,7 +190,19 @@ jobs:
|
||||
files: ghostty-macos-universal.zip
|
||||
token: ${{ secrets.GH_RELEASE_TOKEN }}
|
||||
|
||||
# Create our appcast for Sparkle
|
||||
- name: Generate Appcast
|
||||
env:
|
||||
SPARKLE_KEY: ${{ secrets.PROD_MACOS_SPARKLE_KEY }}
|
||||
run: |
|
||||
echo $SPARKLE_KEY > signing.key
|
||||
sign_update -f signing.key ghostty-macos-universal.zip > sign_update.txt
|
||||
curl -L https://tip.files.ghostty.dev/appcast.xml > appcast.xml
|
||||
python3 ./dist/macos/update_appcast_tip.py
|
||||
test -f appcast_new.xml
|
||||
|
||||
# Update Blob Storage
|
||||
- name: Upload to Blob Storage
|
||||
run: |
|
||||
s3cmd put ghostty-macos-universal.zip s3://ghostty-tip/${GHOSTTY_BUILD}/ghostty-macos-universal.zip
|
||||
s3cmd put appcast_new.xml s3://ghostty-tip/appcast.xml
|
||||
|
75
dist/macos/update_appcast_tip.py
vendored
Normal file
75
dist/macos/update_appcast_tip.py
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
"""
|
||||
This script is used to update the appcast.xml file for Ghostty releases.
|
||||
The script is currently hardcoded to only work for tip releases and therefore
|
||||
doesn't have rich release notes, hardcodes the URL to the tip bucket, etc.
|
||||
|
||||
This expects the following files in the current directory:
|
||||
- sign_update.txt - contains the output from "sign_update" in the Sparkle
|
||||
framework for the current build.
|
||||
- appcast.xml - the existing appcast file.
|
||||
|
||||
And the following environment variables to be set:
|
||||
- GHOSTTY_BUILD - the build number
|
||||
- GHOSTTY_COMMIT - the commit hash
|
||||
|
||||
The script will output a new appcast file called appcast_new.xml.
|
||||
"""
|
||||
|
||||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
from datetime import datetime, timezone
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
build = os.environ["GHOSTTY_BUILD"]
|
||||
commit = os.environ["GHOSTTY_COMMIT"]
|
||||
|
||||
# Read our sign_update output
|
||||
with open("sign_update.txt", "r") as f:
|
||||
# format is a=b b=c etc. create a map of this. values may contain equal
|
||||
# signs, so we can't just split on equal signs.
|
||||
attrs = {}
|
||||
for pair in f.read().split(" "):
|
||||
key, value = pair.split("=", 1)
|
||||
value = value.strip()
|
||||
if value[0] == '"':
|
||||
value = value[1:-1]
|
||||
attrs[key] = value
|
||||
|
||||
# We need to register our namespaces before reading or writing any files.
|
||||
ET.register_namespace("sparkle", "http://www.andymatuschak.org/xml-namespaces/sparkle")
|
||||
|
||||
# Open our existing appcast and find the channel element. This is where
|
||||
# we'll add our new item.
|
||||
et = ET.parse('appcast.xml')
|
||||
channel = et.find("channel")
|
||||
|
||||
# Create the item using some absoultely terrible XML manipulation.
|
||||
item = ET.SubElement(channel, "item")
|
||||
elem = ET.SubElement(item, "title")
|
||||
elem.text = f"Build {build}"
|
||||
elem = ET.SubElement(item, "pubDate")
|
||||
elem.text = now.strftime("%a, %d %b %Y %H:%M:%S %z")
|
||||
elem = ET.SubElement(item, "sparkle:version")
|
||||
elem.text = build
|
||||
elem = ET.SubElement(item, "sparkle:shortVersionString")
|
||||
elem.text = commit
|
||||
elem = ET.SubElement(item, "sparkle:minimumSystemVersion")
|
||||
elem.text = "12.0.0"
|
||||
elem = ET.SubElement(item, "description")
|
||||
elem.text = f"""
|
||||
<p>Automated build from commit <code>{commit}</code>.</p>
|
||||
<p>
|
||||
These are automatic per-commit builds generated from the main Git branch.
|
||||
We do not generate any release notes for these builds. You can view the full
|
||||
commit history
|
||||
<a href="https://github.com/mitchellh/ghostty">on GitHub</a> for all changes.
|
||||
</p>
|
||||
"""
|
||||
elem = ET.SubElement(item, "enclosure")
|
||||
elem.set("url", f"https://tip.files.ghostty.dev/{build}/ghostty-macos-universal.zip")
|
||||
elem.set("type", "application/octet-stream")
|
||||
for key, value in attrs.items():
|
||||
elem.set(key, value)
|
||||
|
||||
# Output the new appcast.
|
||||
et.write("appcast_new.xml", xml_declaration=True, encoding="utf-8")
|
@ -91,6 +91,8 @@
|
||||
<string>A program in Ghostty wants to use speech recognition.</string>
|
||||
<key>NSSystemAdministrationUsageDescription</key>
|
||||
<string>A program in Ghostty requires elevated privileges.</string>
|
||||
<key>SUPublicEDKey</key>
|
||||
<string>wsNcGf5hirwtdXMVnYoxRIX/SqZQLMOsYlD3q3imeok=</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string></string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
|
@ -13,6 +13,8 @@
|
||||
A51BFC1E2B2FB5CE00E92F16 /* About.xib in Resources */ = {isa = PBXBuildFile; fileRef = A51BFC1D2B2FB5CE00E92F16 /* About.xib */; };
|
||||
A51BFC202B2FB64F00E92F16 /* AboutController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51BFC1F2B2FB64F00E92F16 /* AboutController.swift */; };
|
||||
A51BFC222B2FB6B400E92F16 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51BFC212B2FB6B400E92F16 /* AboutView.swift */; };
|
||||
A51BFC272B30F1B800E92F16 /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = A51BFC262B30F1B800E92F16 /* Sparkle */; };
|
||||
A51BFC2B2B30F6BE00E92F16 /* UpdateDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51BFC2A2B30F6BE00E92F16 /* UpdateDelegate.swift */; };
|
||||
A5278A9B2AA05B2600CD3039 /* Ghostty.Input.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5278A9A2AA05B2600CD3039 /* Ghostty.Input.swift */; };
|
||||
A53426352A7DA53D00EBB7A2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53426342A7DA53D00EBB7A2 /* AppDelegate.swift */; };
|
||||
A535B9DA299C569B0017E2E4 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A535B9D9299C569B0017E2E4 /* ErrorView.swift */; };
|
||||
@ -57,6 +59,8 @@
|
||||
A51BFC1D2B2FB5CE00E92F16 /* About.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = About.xib; sourceTree = "<group>"; };
|
||||
A51BFC1F2B2FB64F00E92F16 /* AboutController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutController.swift; sourceTree = "<group>"; };
|
||||
A51BFC212B2FB6B400E92F16 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = "<group>"; };
|
||||
A51BFC282B30F26D00E92F16 /* GhosttyDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = GhosttyDebug.entitlements; sourceTree = "<group>"; };
|
||||
A51BFC2A2B30F6BE00E92F16 /* UpdateDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateDelegate.swift; sourceTree = "<group>"; };
|
||||
A5278A9A2AA05B2600CD3039 /* Ghostty.Input.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.Input.swift; sourceTree = "<group>"; };
|
||||
A53426342A7DA53D00EBB7A2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
A535B9D9299C569B0017E2E4 /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = "<group>"; };
|
||||
@ -102,6 +106,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A51BFC272B30F1B800E92F16 /* Sparkle in Frameworks */,
|
||||
A56B880B2A840447007A0E29 /* Carbon.framework in Frameworks */,
|
||||
A571AB1D2A206FCF00248498 /* GhosttyKit.xcframework in Frameworks */,
|
||||
);
|
||||
@ -120,6 +125,14 @@
|
||||
path = About;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A51BFC292B30F69F00E92F16 /* Update */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A51BFC2A2B30F6BE00E92F16 /* UpdateDelegate.swift */,
|
||||
);
|
||||
path = Update;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A53426362A7DC53000EBB7A2 /* Features */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -128,6 +141,7 @@
|
||||
A5E112912AF73E4D00C6E0C2 /* ClipboardConfirmation */,
|
||||
A534263E2A7DCC5800EBB7A2 /* Settings */,
|
||||
A51BFC1C2B2FB5AB00E92F16 /* About */,
|
||||
A51BFC292B30F69F00E92F16 /* Update */,
|
||||
);
|
||||
path = Features;
|
||||
sourceTree = "<group>";
|
||||
@ -221,6 +235,7 @@
|
||||
A571AB1C2A206FC600248498 /* Ghostty-Info.plist */,
|
||||
A5B30538299BEAAB0047F10C /* Assets.xcassets */,
|
||||
A5B3053D299BEAAB0047F10C /* Ghostty.entitlements */,
|
||||
A51BFC282B30F26D00E92F16 /* GhosttyDebug.entitlements */,
|
||||
A54CD6ED299BEB14008C95BB /* Sources */,
|
||||
A5D495A3299BECBA00DD1313 /* Frameworks */,
|
||||
A5A1F8862A489D7400D1E8BC /* Resources */,
|
||||
@ -280,6 +295,9 @@
|
||||
dependencies = (
|
||||
);
|
||||
name = Ghostty;
|
||||
packageProductDependencies = (
|
||||
A51BFC262B30F1B800E92F16 /* Sparkle */,
|
||||
);
|
||||
productName = Ghostty;
|
||||
productReference = A5B30531299BEAAA0047F10C /* Ghostty.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
@ -308,6 +326,9 @@
|
||||
Base,
|
||||
);
|
||||
mainGroup = A5B30528299BEAAA0047F10C;
|
||||
packageReferences = (
|
||||
A51BFC252B30F1B700E92F16 /* XCRemoteSwiftPackageReference "Sparkle" */,
|
||||
);
|
||||
productRefGroup = A5B30532299BEAAA0047F10C /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
@ -349,6 +370,7 @@
|
||||
A5278A9B2AA05B2600CD3039 /* Ghostty.Input.swift in Sources */,
|
||||
A59630972AEE163600D64628 /* HostingWindow.swift in Sources */,
|
||||
A59630A02AEF6AEB00D64628 /* TerminalManager.swift in Sources */,
|
||||
A51BFC2B2B30F6BE00E92F16 /* UpdateDelegate.swift in Sources */,
|
||||
A53426352A7DA53D00EBB7A2 /* AppDelegate.swift in Sources */,
|
||||
A5CDF1952AAFA19600513312 /* ConfigurationErrorsView.swift in Sources */,
|
||||
A55B7BBC29B6FC330055DE60 /* SurfaceView.swift in Sources */,
|
||||
@ -496,7 +518,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||
CODE_SIGN_ENTITLEMENTS = Ghostty.entitlements;
|
||||
CODE_SIGN_ENTITLEMENTS = GhosttyDebug.entitlements;
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
@ -583,6 +605,25 @@
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
A51BFC252B30F1B700E92F16 /* XCRemoteSwiftPackageReference "Sparkle" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/sparkle-project/Sparkle";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 2.5.1;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
A51BFC262B30F1B800E92F16 /* Sparkle */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = A51BFC252B30F1B700E92F16 /* XCRemoteSwiftPackageReference "Sparkle" */;
|
||||
productName = Sparkle;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = A5B30529299BEAAA0047F10C /* Project object */;
|
||||
}
|
||||
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "sparkle",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/sparkle-project/Sparkle",
|
||||
"state" : {
|
||||
"revision" : "1f07f4096e52f19b5e7abaa697b7fc592b7ff57c",
|
||||
"version" : "2.5.1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"version" : 2
|
||||
}
|
22
macos/GhosttyDebug.entitlements
Normal file
22
macos/GhosttyDebug.entitlements
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.automation.apple-events</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.audio-input</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.camera</key>
|
||||
<true/>
|
||||
<key>com.apple.security.personal-information.addressbook</key>
|
||||
<true/>
|
||||
<key>com.apple.security.personal-information.calendars</key>
|
||||
<true/>
|
||||
<key>com.apple.security.personal-information.location</key>
|
||||
<true/>
|
||||
<key>com.apple.security.personal-information.photos-library</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
@ -1,9 +1,15 @@
|
||||
import AppKit
|
||||
import UserNotifications
|
||||
import OSLog
|
||||
import Sparkle
|
||||
import GhosttyKit
|
||||
|
||||
class AppDelegate: NSObject, ObservableObject, NSApplicationDelegate, UNUserNotificationCenterDelegate, GhosttyAppStateDelegate {
|
||||
class AppDelegate: NSObject,
|
||||
ObservableObject,
|
||||
NSApplicationDelegate,
|
||||
UNUserNotificationCenterDelegate,
|
||||
GhosttyAppStateDelegate
|
||||
{
|
||||
// The application logger. We should probably move this at some point to a dedicated
|
||||
// class/struct but for now it lives here! 🤷♂️
|
||||
static let logger = Logger(
|
||||
@ -12,6 +18,7 @@ class AppDelegate: NSObject, ObservableObject, NSApplicationDelegate, UNUserNoti
|
||||
)
|
||||
|
||||
/// Various menu items so that we can programmatically sync the keyboard shortcut with the Ghostty config.
|
||||
@IBOutlet private var menuCheckForUpdates: NSMenuItem?
|
||||
@IBOutlet private var menuOpenConfig: NSMenuItem?
|
||||
@IBOutlet private var menuReloadConfig: NSMenuItem?
|
||||
@IBOutlet private var menuQuit: NSMenuItem?
|
||||
@ -56,8 +63,18 @@ class AppDelegate: NSObject, ObservableObject, NSApplicationDelegate, UNUserNoti
|
||||
/// Manages our terminal windows.
|
||||
let terminalManager: TerminalManager
|
||||
|
||||
/// Manages updates
|
||||
let updaterController: SPUStandardUpdaterController
|
||||
let updaterDelegate: UpdaterDelegate = UpdaterDelegate()
|
||||
|
||||
override init() {
|
||||
self.terminalManager = TerminalManager(ghostty)
|
||||
terminalManager = TerminalManager(ghostty)
|
||||
updaterController = SPUStandardUpdaterController(
|
||||
startingUpdater: true,
|
||||
updaterDelegate: updaterDelegate,
|
||||
userDriverDelegate: nil
|
||||
)
|
||||
|
||||
super.init()
|
||||
|
||||
ghostty.delegate = self
|
||||
@ -80,6 +97,10 @@ class AppDelegate: NSObject, ObservableObject, NSApplicationDelegate, UNUserNoti
|
||||
"ApplePressAndHoldEnabled": false,
|
||||
])
|
||||
|
||||
// Hook up updater menu
|
||||
menuCheckForUpdates?.target = updaterController
|
||||
menuCheckForUpdates?.action = #selector(SPUStandardUpdaterController.checkForUpdates(_:))
|
||||
|
||||
// Let's launch our first window. We only do this if we have no other windows. It
|
||||
// is possible to have other windows if we're opening a URL since `application(_:openFile:)`
|
||||
// is called before this.
|
||||
|
11
macos/Sources/Features/Update/UpdateDelegate.swift
Normal file
11
macos/Sources/Features/Update/UpdateDelegate.swift
Normal file
@ -0,0 +1,11 @@
|
||||
import Sparkle
|
||||
|
||||
class UpdaterDelegate: NSObject, SPUUpdaterDelegate {
|
||||
func feedURLString(for updater: SPUUpdater) -> String? {
|
||||
// Eventually w want to support multiple channels. Sparkle itself supports
|
||||
// channels but we probably don't want some appcasts in the same file (i.e.
|
||||
// tip) so this would be the place to change that. For now, we hardcode the
|
||||
// tip appcast URL since it is all we support.
|
||||
return "https://tip.files.ghostty.dev/appcast.xml"
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customObject id="bbz-4X-AYv" userLabel="AppDelegate" customClass="AppDelegate" customModule="Ghostty" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="menuCheckForUpdates" destination="GEA-5y-yzH" id="0nV-Tf-nJQ"/>
|
||||
<outlet property="menuClose" destination="DVo-aG-piG" id="R3t-0C-aSU"/>
|
||||
<outlet property="menuCloseAllWindows" destination="yKr-Vi-Yqw" id="Zet-Ir-zbm"/>
|
||||
<outlet property="menuCloseWindow" destination="W5w-UZ-crk" id="6ff-BT-ENV"/>
|
||||
@ -58,6 +59,9 @@
|
||||
<action selector="showAbout:" target="-1" id="tGt-68-tLn"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Check for Updates..." id="GEA-5y-yzH">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
|
||||
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW">
|
||||
<connections>
|
||||
|
Reference in New Issue
Block a user