mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +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:
|
with:
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
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
|
# Setup our S3 client
|
||||||
- name: Setup s3cmd
|
- name: Setup s3cmd
|
||||||
uses: s3-actions/s3cmd@v1.5.0
|
uses: s3-actions/s3cmd@v1.5.0
|
||||||
@ -55,7 +66,7 @@ jobs:
|
|||||||
provider: cloudflare
|
provider: cloudflare
|
||||||
account_id: ${{ secrets.CF_R2_TIP_ACCOUNT_ID }}
|
account_id: ${{ secrets.CF_R2_TIP_ACCOUNT_ID }}
|
||||||
access_key: ${{ secrets.CF_R2_TIP_AWS_KEY }}
|
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
|
# Load Build Number
|
||||||
- name: Build Number
|
- name: Build Number
|
||||||
@ -76,12 +87,18 @@ jobs:
|
|||||||
|
|
||||||
# We inject the "build number" as simply the number of commits since HEAD.
|
# 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.
|
# 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: |
|
run: |
|
||||||
|
# Version Info
|
||||||
/usr/libexec/PlistBuddy -c "Set :GhosttyCommit $GHOSTTY_COMMIT" "macos/build/Release/Ghostty.app/Contents/Info.plist"
|
/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 :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"
|
/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
|
- 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'
|
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 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
|
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
|
# Codesign Sparkle. Some notes here:
|
||||||
/usr/bin/codesign --force -s "$MACOS_CERTIFICATE_NAME" --options runtime macos/build/Release/Ghostty.app -v
|
# - 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"
|
- name: "Notarize app bundle"
|
||||||
env:
|
env:
|
||||||
@ -162,7 +190,19 @@ jobs:
|
|||||||
files: ghostty-macos-universal.zip
|
files: ghostty-macos-universal.zip
|
||||||
token: ${{ secrets.GH_RELEASE_TOKEN }}
|
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
|
# Update Blob Storage
|
||||||
- name: Upload to Blob Storage
|
- name: Upload to Blob Storage
|
||||||
run: |
|
run: |
|
||||||
s3cmd put ghostty-macos-universal.zip s3://ghostty-tip/${GHOSTTY_BUILD}/ghostty-macos-universal.zip
|
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>
|
<string>A program in Ghostty wants to use speech recognition.</string>
|
||||||
<key>NSSystemAdministrationUsageDescription</key>
|
<key>NSSystemAdministrationUsageDescription</key>
|
||||||
<string>A program in Ghostty requires elevated privileges.</string>
|
<string>A program in Ghostty requires elevated privileges.</string>
|
||||||
|
<key>SUPublicEDKey</key>
|
||||||
|
<string>wsNcGf5hirwtdXMVnYoxRIX/SqZQLMOsYlD3q3imeok=</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string></string>
|
<string></string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
A51BFC1E2B2FB5CE00E92F16 /* About.xib in Resources */ = {isa = PBXBuildFile; fileRef = A51BFC1D2B2FB5CE00E92F16 /* About.xib */; };
|
A51BFC1E2B2FB5CE00E92F16 /* About.xib in Resources */ = {isa = PBXBuildFile; fileRef = A51BFC1D2B2FB5CE00E92F16 /* About.xib */; };
|
||||||
A51BFC202B2FB64F00E92F16 /* AboutController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51BFC1F2B2FB64F00E92F16 /* AboutController.swift */; };
|
A51BFC202B2FB64F00E92F16 /* AboutController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51BFC1F2B2FB64F00E92F16 /* AboutController.swift */; };
|
||||||
A51BFC222B2FB6B400E92F16 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51BFC212B2FB6B400E92F16 /* AboutView.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 */; };
|
A5278A9B2AA05B2600CD3039 /* Ghostty.Input.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5278A9A2AA05B2600CD3039 /* Ghostty.Input.swift */; };
|
||||||
A53426352A7DA53D00EBB7A2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53426342A7DA53D00EBB7A2 /* AppDelegate.swift */; };
|
A53426352A7DA53D00EBB7A2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53426342A7DA53D00EBB7A2 /* AppDelegate.swift */; };
|
||||||
A535B9DA299C569B0017E2E4 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A535B9D9299C569B0017E2E4 /* ErrorView.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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
A535B9D9299C569B0017E2E4 /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = "<group>"; };
|
||||||
@ -102,6 +106,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
A51BFC272B30F1B800E92F16 /* Sparkle in Frameworks */,
|
||||||
A56B880B2A840447007A0E29 /* Carbon.framework in Frameworks */,
|
A56B880B2A840447007A0E29 /* Carbon.framework in Frameworks */,
|
||||||
A571AB1D2A206FCF00248498 /* GhosttyKit.xcframework in Frameworks */,
|
A571AB1D2A206FCF00248498 /* GhosttyKit.xcframework in Frameworks */,
|
||||||
);
|
);
|
||||||
@ -120,6 +125,14 @@
|
|||||||
path = About;
|
path = About;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
A51BFC292B30F69F00E92F16 /* Update */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
A51BFC2A2B30F6BE00E92F16 /* UpdateDelegate.swift */,
|
||||||
|
);
|
||||||
|
path = Update;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
A53426362A7DC53000EBB7A2 /* Features */ = {
|
A53426362A7DC53000EBB7A2 /* Features */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -128,6 +141,7 @@
|
|||||||
A5E112912AF73E4D00C6E0C2 /* ClipboardConfirmation */,
|
A5E112912AF73E4D00C6E0C2 /* ClipboardConfirmation */,
|
||||||
A534263E2A7DCC5800EBB7A2 /* Settings */,
|
A534263E2A7DCC5800EBB7A2 /* Settings */,
|
||||||
A51BFC1C2B2FB5AB00E92F16 /* About */,
|
A51BFC1C2B2FB5AB00E92F16 /* About */,
|
||||||
|
A51BFC292B30F69F00E92F16 /* Update */,
|
||||||
);
|
);
|
||||||
path = Features;
|
path = Features;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -221,6 +235,7 @@
|
|||||||
A571AB1C2A206FC600248498 /* Ghostty-Info.plist */,
|
A571AB1C2A206FC600248498 /* Ghostty-Info.plist */,
|
||||||
A5B30538299BEAAB0047F10C /* Assets.xcassets */,
|
A5B30538299BEAAB0047F10C /* Assets.xcassets */,
|
||||||
A5B3053D299BEAAB0047F10C /* Ghostty.entitlements */,
|
A5B3053D299BEAAB0047F10C /* Ghostty.entitlements */,
|
||||||
|
A51BFC282B30F26D00E92F16 /* GhosttyDebug.entitlements */,
|
||||||
A54CD6ED299BEB14008C95BB /* Sources */,
|
A54CD6ED299BEB14008C95BB /* Sources */,
|
||||||
A5D495A3299BECBA00DD1313 /* Frameworks */,
|
A5D495A3299BECBA00DD1313 /* Frameworks */,
|
||||||
A5A1F8862A489D7400D1E8BC /* Resources */,
|
A5A1F8862A489D7400D1E8BC /* Resources */,
|
||||||
@ -280,6 +295,9 @@
|
|||||||
dependencies = (
|
dependencies = (
|
||||||
);
|
);
|
||||||
name = Ghostty;
|
name = Ghostty;
|
||||||
|
packageProductDependencies = (
|
||||||
|
A51BFC262B30F1B800E92F16 /* Sparkle */,
|
||||||
|
);
|
||||||
productName = Ghostty;
|
productName = Ghostty;
|
||||||
productReference = A5B30531299BEAAA0047F10C /* Ghostty.app */;
|
productReference = A5B30531299BEAAA0047F10C /* Ghostty.app */;
|
||||||
productType = "com.apple.product-type.application";
|
productType = "com.apple.product-type.application";
|
||||||
@ -308,6 +326,9 @@
|
|||||||
Base,
|
Base,
|
||||||
);
|
);
|
||||||
mainGroup = A5B30528299BEAAA0047F10C;
|
mainGroup = A5B30528299BEAAA0047F10C;
|
||||||
|
packageReferences = (
|
||||||
|
A51BFC252B30F1B700E92F16 /* XCRemoteSwiftPackageReference "Sparkle" */,
|
||||||
|
);
|
||||||
productRefGroup = A5B30532299BEAAA0047F10C /* Products */;
|
productRefGroup = A5B30532299BEAAA0047F10C /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
@ -349,6 +370,7 @@
|
|||||||
A5278A9B2AA05B2600CD3039 /* Ghostty.Input.swift in Sources */,
|
A5278A9B2AA05B2600CD3039 /* Ghostty.Input.swift in Sources */,
|
||||||
A59630972AEE163600D64628 /* HostingWindow.swift in Sources */,
|
A59630972AEE163600D64628 /* HostingWindow.swift in Sources */,
|
||||||
A59630A02AEF6AEB00D64628 /* TerminalManager.swift in Sources */,
|
A59630A02AEF6AEB00D64628 /* TerminalManager.swift in Sources */,
|
||||||
|
A51BFC2B2B30F6BE00E92F16 /* UpdateDelegate.swift in Sources */,
|
||||||
A53426352A7DA53D00EBB7A2 /* AppDelegate.swift in Sources */,
|
A53426352A7DA53D00EBB7A2 /* AppDelegate.swift in Sources */,
|
||||||
A5CDF1952AAFA19600513312 /* ConfigurationErrorsView.swift in Sources */,
|
A5CDF1952AAFA19600513312 /* ConfigurationErrorsView.swift in Sources */,
|
||||||
A55B7BBC29B6FC330055DE60 /* SurfaceView.swift in Sources */,
|
A55B7BBC29B6FC330055DE60 /* SurfaceView.swift in Sources */,
|
||||||
@ -496,7 +518,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||||
CODE_SIGN_ENTITLEMENTS = Ghostty.entitlements;
|
CODE_SIGN_ENTITLEMENTS = GhosttyDebug.entitlements;
|
||||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
@ -583,6 +605,25 @@
|
|||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
/* End XCConfigurationList section */
|
/* 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 */;
|
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 AppKit
|
||||||
import UserNotifications
|
import UserNotifications
|
||||||
import OSLog
|
import OSLog
|
||||||
|
import Sparkle
|
||||||
import GhosttyKit
|
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
|
// The application logger. We should probably move this at some point to a dedicated
|
||||||
// class/struct but for now it lives here! 🤷♂️
|
// class/struct but for now it lives here! 🤷♂️
|
||||||
static let logger = Logger(
|
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.
|
/// 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 menuOpenConfig: NSMenuItem?
|
||||||
@IBOutlet private var menuReloadConfig: NSMenuItem?
|
@IBOutlet private var menuReloadConfig: NSMenuItem?
|
||||||
@IBOutlet private var menuQuit: NSMenuItem?
|
@IBOutlet private var menuQuit: NSMenuItem?
|
||||||
@ -56,8 +63,18 @@ class AppDelegate: NSObject, ObservableObject, NSApplicationDelegate, UNUserNoti
|
|||||||
/// Manages our terminal windows.
|
/// Manages our terminal windows.
|
||||||
let terminalManager: TerminalManager
|
let terminalManager: TerminalManager
|
||||||
|
|
||||||
|
/// Manages updates
|
||||||
|
let updaterController: SPUStandardUpdaterController
|
||||||
|
let updaterDelegate: UpdaterDelegate = UpdaterDelegate()
|
||||||
|
|
||||||
override init() {
|
override init() {
|
||||||
self.terminalManager = TerminalManager(ghostty)
|
terminalManager = TerminalManager(ghostty)
|
||||||
|
updaterController = SPUStandardUpdaterController(
|
||||||
|
startingUpdater: true,
|
||||||
|
updaterDelegate: updaterDelegate,
|
||||||
|
userDriverDelegate: nil
|
||||||
|
)
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
ghostty.delegate = self
|
ghostty.delegate = self
|
||||||
@ -80,6 +97,10 @@ class AppDelegate: NSObject, ObservableObject, NSApplicationDelegate, UNUserNoti
|
|||||||
"ApplePressAndHoldEnabled": false,
|
"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
|
// 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 possible to have other windows if we're opening a URL since `application(_:openFile:)`
|
||||||
// is called before this.
|
// 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="-3" userLabel="Application" customClass="NSObject"/>
|
||||||
<customObject id="bbz-4X-AYv" userLabel="AppDelegate" customClass="AppDelegate" customModule="Ghostty" customModuleProvider="target">
|
<customObject id="bbz-4X-AYv" userLabel="AppDelegate" customClass="AppDelegate" customModule="Ghostty" customModuleProvider="target">
|
||||||
<connections>
|
<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="menuClose" destination="DVo-aG-piG" id="R3t-0C-aSU"/>
|
||||||
<outlet property="menuCloseAllWindows" destination="yKr-Vi-Yqw" id="Zet-Ir-zbm"/>
|
<outlet property="menuCloseAllWindows" destination="yKr-Vi-Yqw" id="Zet-Ir-zbm"/>
|
||||||
<outlet property="menuCloseWindow" destination="W5w-UZ-crk" id="6ff-BT-ENV"/>
|
<outlet property="menuCloseWindow" destination="W5w-UZ-crk" id="6ff-BT-ENV"/>
|
||||||
@ -58,6 +59,9 @@
|
|||||||
<action selector="showAbout:" target="-1" id="tGt-68-tLn"/>
|
<action selector="showAbout:" target="-1" id="tGt-68-tLn"/>
|
||||||
</connections>
|
</connections>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
|
<menuItem title="Check for Updates..." id="GEA-5y-yzH">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
</menuItem>
|
||||||
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
|
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
|
||||||
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW">
|
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW">
|
||||||
<connections>
|
<connections>
|
||||||
|
Reference in New Issue
Block a user