Merge pull request #7750 from nextcloud/feature/sparkle-2

updater: Upgrade to Sparkle 2
This commit is contained in:
Matthieu Gallien 2025-01-15 11:27:07 +01:00 committed by GitHub
commit e4d7bbe958
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 78 additions and 65 deletions

View File

@ -126,17 +126,31 @@ func codesignClientAppBundle(
// We need to strip these out manually.
let sparkleFrameworkPath = "\(frameworksPath)/Sparkle.framework"
if FileManager.default.fileExists(atPath: "\(sparkleFrameworkPath)/Resources/Autoupdate.app") {
print("Code-signing Sparkle autoupdater app (without entitlements)...")
try recursivelyCodesign(
path: "\(sparkleFrameworkPath)/Resources/Autoupdate.app",
if FileManager.default.fileExists(atPath: sparkleFrameworkPath) {
print("Code-signing Sparkle...")
try codesign(
identity: codeSignIdentity,
options: "--timestamp --force --verbose=4 --options runtime --deep"
path: "\(sparkleFrameworkPath)/Versions/B/XPCServices/Installer.xpc",
options: "-f -o runtime"
)
try codesign(
identity: codeSignIdentity,
path: "\(sparkleFrameworkPath)/Versions/B/XPCServices/Downloader.xpc",
options: "-f -o runtime --preserve-metadata=entitlements"
)
try codesign(
identity: codeSignIdentity,
path: "\(sparkleFrameworkPath)/Versions/B/Autoupdate",
options: "-f -o runtime"
)
try codesign(
identity: codeSignIdentity,
path: "\(sparkleFrameworkPath)/Versions/B/Updater.app",
options: "-f -o runtime"
)
try codesign(
identity: codeSignIdentity, path: sparkleFrameworkPath, options: "-f -o runtime"
)
print("Re-codesigning Sparkle library...")
try codesign(identity: codeSignIdentity, path: "\(sparkleFrameworkPath)/Sparkle")
} else {
print("Build does not have Sparkle, skipping.")
}

View File

@ -60,7 +60,7 @@ struct Build: ParsableCommand {
@Option(name: [.long], help: "Sparkle download URL.")
var sparkleDownloadUrl =
"https://github.com/sparkle-project/Sparkle/releases/download/1.27.3/Sparkle-1.27.3.tar.xz"
"https://github.com/sparkle-project/Sparkle/releases/download/2.6.4/Sparkle-2.6.4.tar.xz"
@Option(name: [.long], help: "Git clone command; include options such as depth.")
var gitCloneCommand = "git clone --depth=1"

View File

@ -15,7 +15,6 @@
#include <Cocoa/Cocoa.h>
#include <Sparkle/Sparkle.h>
#include <Sparkle/SUUpdater.h>
#include <AppKit/NSApplication.h>
#include "common/utility.h"
@ -34,7 +33,7 @@ public:
~SparkleInterface()
{
[updater release];
[updaterController release];
[delegate release];
}
@ -45,7 +44,7 @@ public:
emit q->statusChanged();
}
SUUpdater* updater;
SPUStandardUpdaterController *updaterController;
NCSparkleUpdaterDelegate *delegate;
private:
@ -53,12 +52,12 @@ private:
};
@interface NCSparkleUpdaterDelegate : NSObject <SUUpdaterDelegate>
@interface NCSparkleUpdaterDelegate : NSObject <SPUUpdaterDelegate>
@property (readwrite, assign) OCC::SparkleUpdater::SparkleInterface *owner;
@property (readwrite, retain) NSString *feedURLString;
- (instancetype)initWithOwner:(OCC::SparkleUpdater::SparkleInterface *)owner;
- (BOOL)updaterMayCheckForUpdates:(SUUpdater *)bundle;
@end
@ -75,21 +74,15 @@ private:
- (BOOL)backgroundUpdateChecksAllowed
{
BOOL allowUpdateCheck = OCC::ConfigFile().skipUpdateCheck() ? NO : YES;
const BOOL allowUpdateCheck = OCC::ConfigFile().skipUpdateCheck() ? NO : YES;
qCInfo(OCC::lcUpdater) << "Updater may check for updates:" << (allowUpdateCheck ? "YES" : "NO");
return allowUpdateCheck;
}
- (BOOL)updaterMayCheckForUpdates:(SUUpdater *)bundle
{
Q_UNUSED(bundle)
return [self backgroundUpdateChecksAllowed];
}
- (BOOL)updaterShouldShowUpdateAlertForScheduledUpdate:(SUUpdater *)updater forItem:(SUAppcastItem *)item
- (BOOL)updater:(nonnull SPUUpdater *)updater mayPerformUpdateCheck:(SPUUpdateCheck)updateCheck error:(NSError **)error
{
Q_UNUSED(updater)
Q_UNUSED(item)
Q_UNUSED(updateCheck)
return [self backgroundUpdateChecksAllowed];
}
@ -100,12 +93,12 @@ private:
}
// Sent when a valid update is found by the update driver.
- (void)updater:(SUUpdater *)updater didFindValidUpdate:(SUAppcastItem *)update
- (void)updater:(nonnull SPUUpdater *)updater didFindValidUpdate:(nonnull SUAppcastItem *)item
{
Q_UNUSED(updater)
Q_UNUSED(update)
Q_UNUSED(item)
const auto versionQstring = QString::fromNSString(update.displayVersionString);
const auto versionQstring = QString::fromNSString(item.displayVersionString);
const auto message = QObject::tr("Found a valid update: version %1", "%1 is version number").arg(versionQstring);
[self notifyStateChange:OCC::SparkleUpdater::State::AwaitingUserInput
@ -113,7 +106,7 @@ private:
}
// Sent when a valid update is not found.
- (void)updaterDidNotFindUpdate:(SUUpdater *)updater
- (void)updaterDidNotFindUpdate:(nonnull SPUUpdater *)updater
{
Q_UNUSED(updater)
[self notifyStateChange:OCC::SparkleUpdater::State::Idle
@ -121,7 +114,7 @@ private:
}
// Sent immediately before installing the specified update.
- (void)updater:(SUUpdater *)updater willInstallUpdate:(SUAppcastItem *)update
- (void)updater:(nonnull SPUUpdater *)updater willInstallUpdate:(nonnull SUAppcastItem *)update
{
Q_UNUSED(updater)
@ -132,7 +125,7 @@ private:
displayStatus:message];
}
- (void)updater:(SUUpdater *)updater didAbortWithError:(NSError *)error
- (void)updater:(nonnull SPUUpdater *)updater didAbortWithError:(nonnull NSError *)error
{
Q_UNUSED(updater)
@ -142,7 +135,7 @@ private:
displayStatus:message];
}
- (void)updater:(SUUpdater *)updater didFinishLoadingAppcast:(SUAppcast *)appcast
- (void)updater:(nonnull SPUUpdater *)updater didFinishLoadingAppcast:(nonnull SUAppcast *)appcast
{
Q_UNUSED(updater)
Q_UNUSED(appcast)
@ -150,30 +143,32 @@ private:
displayStatus:QObject::tr("Finished loading appcast.")];
}
- (void)updater:(SUUpdater *)updater didDismissUpdateAlertPermanently:(BOOL)permanently forItem:(nonnull SUAppcastItem *)item
{
Q_UNUSED(updater)
const auto permanencyString = permanently ? QObject::tr("Permanently") : QObject::tr("Temporarily");
const auto versionQstring = QString::fromNSString(item.displayVersionString);
const auto message = QObject::tr("%1 dismissed %2 update", "%1 is permanently or temporarily, %2 is version number").arg(permanencyString, versionQstring);
[self notifyStateChange:OCC::SparkleUpdater::State::Idle
displayStatus:message];
}
- (void)updater:(nonnull SUUpdater *)updater userDidSkipThisVersion:(nonnull SUAppcastItem *)item
- (void)updater:(nonnull SPUUpdater *)updater
userDidMakeChoice:(SPUUserUpdateChoice)choice
forUpdate:(nonnull SUAppcastItem *)item
state:(nonnull SPUUserUpdateState *)state
{
Q_UNUSED(updater)
const auto versionQstring = QString::fromNSString(item.displayVersionString);
const auto message = QObject::tr("Update version %1 will not be applied as it was chosen to be skipped.", "%1 is version number").arg(versionQstring);
QString message;
[self notifyStateChange:OCC::SparkleUpdater::State::Idle
displayStatus:message];
switch(choice) {
case SPUUserUpdateChoiceSkip:
message = QObject::tr("Update version %1 will not be applied as it was chosen to be skipped.", "%1 is version number").arg(versionQstring);
break;
case SPUUserUpdateChoiceInstall:
message = QObject::tr("Update version %1 will be installed.", "%1 is version number").arg(versionQstring);
break;
case SPUUserUpdateChoiceDismiss:
message = QObject::tr("Update version %1 will not be applied as it was dismissed.", "%1 is version number").arg(versionQstring);
break;
}
[self notifyStateChange:OCC::SparkleUpdater::State::Idle displayStatus:message];
}
- (void)updater:(nonnull SUUpdater *)updater willDownloadUpdate:(nonnull SUAppcastItem *)item withRequest:(nonnull NSMutableURLRequest *)request
- (void)updater:(nonnull SPUUpdater *)updater willDownloadUpdate:(nonnull SUAppcastItem *)item withRequest:(nonnull NSMutableURLRequest *)request
{
Q_UNUSED(updater)
Q_UNUSED(request)
@ -185,7 +180,7 @@ private:
displayStatus:message];
}
- (void)updater:(nonnull SUUpdater *)updater didDownloadUpdate:(nonnull SUAppcastItem *)item
- (void)updater:(nonnull SPUUpdater *)updater didDownloadUpdate:(nonnull SUAppcastItem *)item
{
Q_UNUSED(updater)
@ -196,7 +191,7 @@ private:
displayStatus:message];
}
- (void)updater:(nonnull SUUpdater *)updater failedToDownloadUpdate:(nonnull SUAppcastItem *)item error:(nonnull NSError *)error
- (void)updater:(nonnull SPUUpdater *)updater failedToDownloadUpdate:(nonnull SUAppcastItem *)item error:(nonnull NSError *)error
{
Q_UNUSED(updater)
@ -208,7 +203,7 @@ private:
displayStatus:message];
}
- (void)updater:(nonnull SUUpdater *)updater willExtractUpdate:(nonnull SUAppcastItem *)item
- (void)updater:(nonnull SPUUpdater *)updater willExtractUpdate:(nonnull SUAppcastItem *)item
{
Q_UNUSED(updater)
@ -219,7 +214,7 @@ private:
displayStatus:message];
}
- (void)updater:(nonnull SUUpdater *)updater didExtractUpdate:(nonnull SUAppcastItem *)item
- (void)updater:(nonnull SPUUpdater *)updater didExtractUpdate:(nonnull SUAppcastItem *)item
{
Q_UNUSED(updater)
@ -230,13 +225,19 @@ private:
displayStatus:message];
}
- (void)userDidCancelDownload:(SUUpdater *)updater
- (void)userDidCancelDownload:(SPUUpdater *)updater
{
Q_UNUSED(updater);
[self notifyStateChange:OCC::SparkleUpdater::State::Idle
displayStatus:QObject::tr("Update download cancelled.")];
}
- (NSString *)feedURLStringForUpdater:(SPUUpdater *)updater
{
Q_UNUSED(updater)
return self.feedURLString;
}
@end
@ -250,27 +251,25 @@ SparkleUpdater::SparkleUpdater(const QUrl& appCastUrl)
_interface->delegate = [[NCSparkleUpdaterDelegate alloc] initWithOwner:_interface.get()];
[_interface->delegate retain];
_interface->updater = [SUUpdater sharedUpdater];
[_interface->updater setDelegate:_interface->delegate];
[_interface->updater setAutomaticallyChecksForUpdates:YES];
[_interface->updater setAutomaticallyDownloadsUpdates:NO];
[_interface->updater setSendsSystemProfile:NO];
[_interface->updater resetUpdateCycle];
[_interface->updater retain];
_interface->updaterController =
[[SPUStandardUpdaterController alloc] initWithStartingUpdater:YES
updaterDelegate:_interface->delegate
userDriverDelegate:nil];
[_interface->updaterController retain];
setUpdateUrl(appCastUrl);
// Sparkle 1.8 required
const auto userAgentString = QString::fromUtf8(Utility::userAgentString());
NSString *userAgent = userAgentString.toNSString();
[_interface->updater setUserAgentString: userAgent];
NSString *const userAgent = userAgentString.toNSString();
_interface->updaterController.updater.userAgentString = userAgent;
}
SparkleUpdater::~SparkleUpdater() = default;
void SparkleUpdater::setUpdateUrl(const QUrl &url)
{
[_interface->updater setFeedURL:url.toNSURL()];
_interface->delegate.feedURLString = url.toNSURL().absoluteString;
}
bool SparkleUpdater::autoUpdaterAllowed()
@ -295,7 +294,7 @@ void SparkleUpdater::checkForUpdate()
{
qCInfo(OCC::lcUpdater) << "Checking for updates.";
if (autoUpdaterAllowed()) {
[_interface->updater checkForUpdates: NSApp];
[_interface->updaterController.updater checkForUpdates];
}
}
@ -303,7 +302,7 @@ void SparkleUpdater::backgroundCheckForUpdate()
{
if (autoUpdaterAllowed() && !ConfigFile().skipUpdateCheck()) {
qCInfo(OCC::lcUpdater) << "launching background check";
[_interface->updater checkForUpdatesInBackground];
[_interface->updaterController.updater checkForUpdatesInBackground];
} else {
qCInfo(OCC::lcUpdater) << "not launching background check, auto updater not allowed or update check skipped in config";
}