Skip to content

Commit

Permalink
Use sparkle framework for auto-updates
Browse files Browse the repository at this point in the history
  • Loading branch information
mr-pennyworth committed Jul 8, 2024
1 parent 68985d0 commit 73d01f8
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 12 deletions.
28 changes: 27 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ jobs:

- name: Build App
if: env.TAG_EXISTS == 'false'
run: xcodebuild -project AlfredExtraPane.xcodeproj -configuration Release -scheme AlfredExtraPane -derivedDataPath DerivedData build
# Don't code sign as sparkle complains that the signature is corrupt.
# At this moment, we don't see any value in figuring out how exactly
# the code signature is corrupt.
run: xcodebuild -project AlfredExtraPane.xcodeproj -configuration Release -scheme AlfredExtraPane -derivedDataPath DerivedData clean build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO

- name: Copy Built App
if: env.TAG_EXISTS == 'false'
Expand All @@ -72,6 +75,29 @@ jobs:
if: env.TAG_EXISTS == 'false'
run: zip -r AlfredExtraPane.app.zip AlfredExtraPane.app

- name: Get Sparkle Private Signing Key
if: env.TAG_EXISTS == 'false'
env:
SPARKLE_PRIVATE_SIGNING_KEY: ${{ secrets.SPARKLE_PRIVATE_SIGNING_KEY }}
run: |
echo "$SPARKLE_PRIVATE_SIGNING_KEY" > sparkle_private_signing.key
- name: Generate Appcast XML
if: env.TAG_EXISTS == 'false'
run: bash gen-appcast.sh

- name: Upload Appcast XML
if: env.TAG_EXISTS == 'false'
id: upload-appcast-xml
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./appcast.xml
asset_name: appcast.xml
asset_content_type: application/xml

- name: Upload Release Asset
if: env.TAG_EXISTS == 'false'
id: upload-release-asset
Expand Down
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ DerivedData
xcuserdata/
xcuserdata
xcuserdata/
Sparkle/
*.key
*.pyc
*.xcworkspace
.idea
.latest-tag
.release-version
AlfredExtraPane.app.zip
appcast.xml
.DS_Store
21 changes: 19 additions & 2 deletions AlfredExtraPane.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
D08B6EE5266F31790099EB36 /* Pane.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08B6EE4266F31790099EB36 /* Pane.swift */; };
D08B6EE7266F9B520099EB36 /* PanePositionCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08B6EE6266F9B520099EB36 /* PanePositionCodable.swift */; };
D0B3E0A42B8A1F3A008EA695 /* AlfredExtraPaneTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B3E0A32B8A1F3A008EA695 /* AlfredExtraPaneTests.swift */; };
D0E764282C3C1E6D00E662F3 /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = D0E764272C3C1E6D00E662F3 /* Sparkle */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -69,6 +70,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D0E764282C3C1E6D00E662F3 /* Sparkle in Frameworks */,
D040E2422667A4FC00495B2D /* Alfred in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -154,6 +156,7 @@
name = AlfredExtraPane;
packageProductDependencies = (
D040E2412667A4FC00495B2D /* Alfred */,
D0E764272C3C1E6D00E662F3 /* Sparkle */,
);
productName = AlfredExtraPane;
productReference = D03EA8CF25551E0400D3656E /* AlfredExtraPane.app */;
Expand Down Expand Up @@ -207,6 +210,7 @@
mainGroup = D03EA8C625551E0400D3656E;
packageReferences = (
D040E2402667A4FC00495B2D /* XCRemoteSwiftPackageReference "AlfredSwift" */,
D0E764262C3C1E6D00E662F3 /* XCRemoteSwiftPackageReference "Sparkle" */,
);
productRefGroup = D03EA8D025551E0400D3656E /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -397,8 +401,8 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 0.1.8;
ONLY_ACTIVE_ARCH = NO;
MARKETING_VERSION = 0.1.7;
OTHER_CODE_SIGN_FLAGS = "--deep";
PRODUCT_BUNDLE_IDENTIFIER = mr.pennyworth.AlfredExtraPane;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand All @@ -418,8 +422,8 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 0.1.8;
ONLY_ACTIVE_ARCH = NO;
MARKETING_VERSION = 0.1.7;
OTHER_CODE_SIGN_FLAGS = "--deep";
PRODUCT_BUNDLE_IDENTIFIER = mr.pennyworth.AlfredExtraPane;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand Down Expand Up @@ -513,6 +517,14 @@
minimumVersion = 0.1.9;
};
};
D0E764262C3C1E6D00E662F3 /* XCRemoteSwiftPackageReference "Sparkle" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/sparkle-project/Sparkle";
requirement = {
kind = exactVersion;
version = 2.6.4;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
Expand All @@ -521,6 +533,11 @@
package = D040E2402667A4FC00495B2D /* XCRemoteSwiftPackageReference "AlfredSwift" */;
productName = Alfred;
};
D0E764272C3C1E6D00E662F3 /* Sparkle */ = {
isa = XCSwiftPackageProductDependency;
package = D0E764262C3C1E6D00E662F3 /* XCRemoteSwiftPackageReference "Sparkle" */;
productName = Sparkle;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = D03EA8C725551E0400D3656E /* Project object */;
Expand Down
6 changes: 6 additions & 0 deletions AlfredExtraPane/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,11 @@
<true/>
<key>NSSupportsSuddenTermination</key>
<true/>
<key>SUEnableAutomaticChecks</key>
<true/>
<key>SUFeedURL</key>
<string>https://github.com/mr-pennyworth/alfred-extra-pane/releases/latest/download/appcast.xml</string>
<key>SUPublicEDKey</key>
<string>BAurF5ltFG9az2kGR/+01BftlDBsNg/vm7NGgdP4JNI=</string>
</dict>
</plist>
31 changes: 22 additions & 9 deletions AlfredExtraPane/main.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Alfred
import AppKit
import Foundation

import Sparkle

class AppDelegate: NSObject, NSApplicationDelegate {
let fs = FileManager.default
Expand All @@ -11,16 +11,21 @@ class AppDelegate: NSObject, NSApplicationDelegate {
workflowUID: "*"
)
var statusItem: NSStatusItem?

let updaterController = SPUStandardUpdaterController(
startingUpdater: true,
updaterDelegate: nil,
userDriverDelegate: nil
)

override init() {
super.init()
let confs: [PaneConfig] =
(try? read(contentsOf: configFile())) ?? [defaultConfig]
panes = confs.map { Pane(config: $0) }
}

func applicationDidFinishLaunching(_ notification: Notification) {
setupMenubarExtra()
setupMenubarExtra()
}

func application(_ application: NSApplication, open urls: [URL]) {
Expand Down Expand Up @@ -55,7 +60,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}
return conf
}

func setupMenubarExtra() {
let appName =
Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as! String
Expand All @@ -70,18 +75,26 @@ class AppDelegate: NSObject, NSApplicationDelegate {
button.image = image
button.toolTip = appName
}

let menu = NSMenu()
menu.addItem(NSMenuItem(
title: "Check for Updates",
action: #selector(checkForUpdates),
keyEquivalent: "u"
))
menu.addItem(NSMenuItem(
title: "Restart " + appName,
action: #selector(restart),
keyEquivalent: "r"
))

statusItem?.menu = menu
}



@objc func checkForUpdates() {
updaterController.checkForUpdates(nil)
}

@objc func restart() {
let task = Process()
task.launchPath = "/usr/bin/open"
Expand Down
82 changes: 82 additions & 0 deletions gen-appcast.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
REPO="https://github.com/mr-pennyworth/alfred-extra-pane"
SPARKLE_RELEASES="https://github.com/sparkle-project/Sparkle/releases/download"
APPCAST_XML="appcast.xml"
vSPARKLE="2.6.4"
SPARKLE_DIST_ZIP="Sparkle-$vSPARKLE.tar.xz"
SPARKLE_DIST_URL="$SPARKLE_RELEASES/$vSPARKLE/$SPARKLE_DIST_ZIP"

# Download the sparkle distribution, extract it, and copy the signer binary
# so that we can sign the AlfredExtraPane.app.zip file.
function download_sparkle_dist() {
if [ ! -d Sparkle ]; then
wget "$SPARKLE_DIST_URL"
mkdir -p Sparkle
tar -xf "$SPARKLE_DIST_ZIP" -C Sparkle
fi
}

# latest-tag returns the latest tag in the git repo.
# it also caches the result in a file to avoid running git commands every time.
function latest_tag() {
if [ -f .latest-tag ]; then
cat .latest-tag
else
git fetch --tags
git describe --tags "$(git rev-list --tags --max-count=1)" > .latest-tag
cat .latest-tag
fi
}

function release_version() {
if [ -f .release-version ]; then
cat .release-version
else
xcodebuild -showBuildSettings \
| grep MARKETING_VERSION \
| cut -f2 -d = \
| tr -d '[:space:]' > .release-version
cat .release-version
fi
}

function latest_appcast_url() {
echo "$REPO/releases/download/$(latest_tag)/$APPCAST_XML"
}

function signature() {
./Sparkle/bin/sign_update \
AlfredExtraPane.app.zip -f sparkle_private_signing.key
}

function new_appcast_item() {
new_release="$(release_version)"
cat <<EOF
<item>
<title>Version ${new_release}</title>
<pubDate>$(date -u +"%a, %d %b %Y %H:%M:%S %z")</pubDate>
<enclosure
url="$REPO/releases/download/${new_release}/AlfredExtraPane.app.zip"
sparkle:version="${new_release}"
sparkle:shortVersionString="${new_release}"
$(signature)
type="application/octet-stream"/>
</item>
EOF
}

# Download the appcast.xml file, then add the new appcast item to it.
# Finally, upload the updated appcast.xml file to the repo.
function update_appcast() {
appcast_url="$(latest_appcast_url)"
rm -f $APPCAST_XML
wget "$appcast_url"

head -n6 $APPCAST_XML
new_appcast_item
tail -n+7 $APPCAST_XML
}

download_sparkle_dist
update_appcast > appcast.new.xml
mv appcast.new.xml $APPCAST_XML

0 comments on commit 73d01f8

Please sign in to comment.