Skip to content

Commit dd93743

Browse files
authored
Add support for extracting Apple Archives (.aar files) (#2586)
Check `man aa` and https://developer.apple.com/documentation/applearchive for more details. This is an efficient Apple custom archive format available since versions of macOS 10.15. In macOS 10.15, this utility used to be called yaa.
1 parent 97a8f5a commit dd93743

File tree

7 files changed

+54
-10
lines changed

7 files changed

+54
-10
lines changed

Autoupdate/SUPipedUnarchiver.m

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ @implementation SUPipedUnarchiver
2727
NSArray <NSString *> *extractTXZ = extractTGZ;
2828

2929
// Note: keep this list in sync with generate_appcast's unarchiveUpdates()
30-
NSDictionary <NSString *, NSArray<NSString *> *> *extractCommandDictionary =
31-
@{
30+
NSMutableDictionary <NSString *, NSArray<NSString *> *> *extractCommandDictionary =
31+
[@{
3232
@".zip" : @[@"/usr/bin/ditto", @"-x",@"-k",@"-"],
3333
@".tar" : @[@"/usr/bin/tar", @"-xC"],
3434
@".tar.gz" : extractTGZ,
@@ -37,8 +37,28 @@ @implementation SUPipedUnarchiver
3737
@".tbz" : extractTBZ,
3838
@".tar.xz" : extractTXZ,
3939
@".txz" : extractTXZ,
40-
@".tar.lzma" : extractTXZ
41-
};
40+
@".tar.lzma" : extractTXZ,
41+
} mutableCopy];
42+
43+
// At least the latest versions of 10.15 understand how to extract aar files
44+
// Versions before 10.15 do not understand extracting newly created aar files
45+
// Note encrypted aea files are supported in macOS 12 onwards, if we ever want to support those one day
46+
if (@available(macOS 10.15.7, *)) {
47+
NSString *appleArchiveCommand;
48+
if (@available(macOS 11, *)) {
49+
appleArchiveCommand = @"/usr/bin/aa";
50+
} else {
51+
// In 10.15 the utility was named yaa, which was later renamed to aar
52+
appleArchiveCommand = @"/usr/bin/yaa";
53+
}
54+
55+
NSArray <NSString *> *extractAppleArchive = @[appleArchiveCommand, @"extract", @"-d"];
56+
57+
[extractCommandDictionary addEntriesFromDictionary:@{
58+
@".aar" : extractAppleArchive,
59+
@".yaa" : extractAppleArchive,
60+
}];
61+
}
4262

4363
NSString *lastPathComponent = [path lastPathComponent];
4464
for (NSString *currentType in extractCommandDictionary)
@@ -93,10 +113,12 @@ - (void)extractArchivePipingDataToCommand:(NSString *)command arguments:(NSArray
93113
@autoreleasepool {
94114
NSString *destination = _extractionDirectory;
95115

116+
NSFileManager *fileManager = [NSFileManager defaultManager];
117+
96118
SULog(SULogLevelDefault, @"Extracting using '%@' '%@' < '%@' '%@'", command, [args componentsJoinedByString:@"' '"], _archivePath, destination);
97119

98120
// Get the file size.
99-
NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:_archivePath error:nil];
121+
NSDictionary *attributes = [fileManager attributesOfItemAtPath:_archivePath error:nil];
100122
NSUInteger expectedLength = [(NSNumber *)[attributes objectForKey:NSFileSize] unsignedIntegerValue];
101123

102124
if (expectedLength == 0) {

Configurations/ConfigCommon.xcconfig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,13 @@ SPARKLE_ICON_NAME = AppIcon
9898
// If you change any of these version details, you must increase CURRENT_PROJECT_VERSION
9999
// These variables must have a space after the '=' too
100100
SPARKLE_VERSION_MAJOR = 2
101-
SPARKLE_VERSION_MINOR = 6
102-
SPARKLE_VERSION_PATCH = 3
101+
SPARKLE_VERSION_MINOR = 7
102+
SPARKLE_VERSION_PATCH = 0
103103

104104
// This should be in SemVer format or empty, ie. "-beta.1"
105105
// These variables must have a space after the '=' too
106-
SPARKLE_VERSION_SUFFIX =
107-
CURRENT_PROJECT_VERSION = 2039
106+
SPARKLE_VERSION_SUFFIX = -beta.1
107+
CURRENT_PROJECT_VERSION = 2040
108108

109109
MARKETING_VERSION = $(SPARKLE_VERSION_MAJOR).$(SPARKLE_VERSION_MINOR).$(SPARKLE_VERSION_PATCH)$(SPARKLE_VERSION_SUFFIX)
110110
ALWAYS_SEARCH_USER_PATHS = NO

Sparkle.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,8 @@
335335
726F2CE61BC9C33D001971A4 /* SUOperatingSystem.m in Sources */ = {isa = PBXBuildFile; fileRef = 726F2CE41BC9C33D001971A4 /* SUOperatingSystem.m */; };
336336
726F2CE81BC9C48F001971A4 /* SUConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 61299A5F09CA6EB100B7442F /* SUConstants.m */; };
337337
726F2CEB1BC9C733001971A4 /* SUConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 61299A5F09CA6EB100B7442F /* SUConstants.m */; };
338+
726FC0362C1E787A00177986 /* SparkleTestCodeSignApp.aar in Resources */ = {isa = PBXBuildFile; fileRef = 726FC0352C1E787A00177986 /* SparkleTestCodeSignApp.aar */; };
339+
726FC0382C1E96AA00177986 /* SparkleTestCodeSignApp.enc.aar in Resources */ = {isa = PBXBuildFile; fileRef = 726FC0372C1E96AA00177986 /* SparkleTestCodeSignApp.enc.aar */; };
338340
727DBAE526B5BBFD00111F0C /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = 727DBAE426B5BBFD00111F0C /* ArgumentParser */; };
339341
727DBAE726B5C47800111F0C /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = 727DBAE626B5C47800111F0C /* ArgumentParser */; };
340342
727DBAE926B5C48A00111F0C /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = 727DBAE826B5C48A00111F0C /* ArgumentParser */; };
@@ -1330,6 +1332,8 @@
13301332
726E4A361C89116000C57C6A /* SPUStandardUserDriverDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPUStandardUserDriverDelegate.h; sourceTree = "<group>"; };
13311333
726F2CE31BC9C33D001971A4 /* SUOperatingSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SUOperatingSystem.h; sourceTree = "<group>"; };
13321334
726F2CE41BC9C33D001971A4 /* SUOperatingSystem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SUOperatingSystem.m; sourceTree = "<group>"; };
1335+
726FC0352C1E787A00177986 /* SparkleTestCodeSignApp.aar */ = {isa = PBXFileReference; lastKnownFileType = file; path = SparkleTestCodeSignApp.aar; sourceTree = "<group>"; };
1336+
726FC0372C1E96AA00177986 /* SparkleTestCodeSignApp.enc.aar */ = {isa = PBXFileReference; lastKnownFileType = file; path = SparkleTestCodeSignApp.enc.aar; sourceTree = "<group>"; };
13331337
726FD2CB25F4BE5F00123BC6 /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = fa.lproj/MainMenu.strings; sourceTree = "<group>"; };
13341338
726FD2CC25F4BE5F00123BC6 /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = fa.lproj/Sparkle.strings; sourceTree = "<group>"; };
13351339
727F340A2605321D00020E85 /* SULog+NSError.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SULog+NSError.m"; sourceTree = "<group>"; };
@@ -1868,6 +1872,8 @@
18681872
729F7ECD27409076004592DC /* SparkleTestCodeSignApp_bad_extraneous.zip */,
18691873
72CCDEBD27421FD500B53718 /* SparkleTestCodeSignApp_bad_header.zip */,
18701874
F8761EB21ADC50EB000C9034 /* SparkleTestCodeSignApp.zip */,
1875+
726FC0352C1E787A00177986 /* SparkleTestCodeSignApp.aar */,
1876+
726FC0372C1E96AA00177986 /* SparkleTestCodeSignApp.enc.aar */,
18711877
72EB735E29BE981300FBCEE7 /* DevSignedApp.zip */,
18721878
72EB736029BEB36100FBCEE7 /* DevSignedAppVersion2.zip */,
18731879
14958C6C19AEBC610061B14F /* test-pubkey.pem */,
@@ -3191,10 +3197,12 @@
31913197
5AF6C74F1AEA46D10014A3AB /* test.pkg in Resources */,
31923198
72EB735F29BE981300FBCEE7 /* DevSignedApp.zip in Resources */,
31933199
72BC6C3D275027BF0083F14B /* SparkleTestCodeSign_apfs.dmg in Resources */,
3200+
726FC0382C1E96AA00177986 /* SparkleTestCodeSignApp.enc.aar in Resources */,
31943201
720DC50627A62CDC00DFF3EC /* testappcast_minimumAutoupdateVersionSkipping2.xml in Resources */,
31953202
5AD0FA7F1C73F2E2004BCEFF /* testappcast.xml in Resources */,
31963203
FA30773D24CBC295007BA37D /* testlocalizedreleasenotesappcast.xml in Resources */,
31973204
72CCDEBE27421FD500B53718 /* SparkleTestCodeSignApp_bad_header.zip in Resources */,
3205+
726FC0362C1E787A00177986 /* SparkleTestCodeSignApp.aar in Resources */,
31983206
722545B626805FF80036465C /* testappcast_info_updates.xml in Resources */,
31993207
7202DC9A269ABD3500737EC4 /* testappcast_phasedRollout.xml in Resources */,
32003208
5F1510A21C96E591006E1629 /* testnamespaces.xml in Resources */,
618 KB
Binary file not shown.
368 KB
Binary file not shown.

Tests/SUUnarchiverTest.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,4 +157,18 @@ class SUUnarchiverTest: XCTestCase
157157
self.unarchiveTestAppWithExtension("pkg", resourceName: "test", expectingInstallationType: SPUInstallationTypeApplication, expectingSuccess: false)
158158
}
159159
#endif
160+
161+
func testUnarchivingAppleArchive() {
162+
self.unarchiveTestAppWithExtension("aar", resourceName: "SparkleTestCodeSignApp")
163+
}
164+
165+
// If we support encrypted archives one day we will use "aea" file extension
166+
// Password to this archive is whatisgoingonforeveroneday!
167+
func testUnarchivingEncryptedAppleArchiveWithoutPassword() {
168+
signal(SIGPIPE, SIG_IGN)
169+
170+
self.unarchiveTestAppWithExtension("enc.aar", resourceName: "SparkleTestCodeSignApp", expectingSuccess: false)
171+
172+
signal(SIGPIPE, SIG_DFL)
173+
}
160174
}

generate_appcast/Unarchive.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func unarchiveUpdates(archivesSourceDir: URL, archivesDestDir: URL, disableNeste
5252
let itemURL = archivesSourceDir.appendingPathComponent(item)
5353
let fileExtension = itemURL.pathExtension
5454
// Note: keep this list in sync with SUPipedUnarchiver
55-
guard ["zip", "tar", "gz", "tgz", "bz2", "tbz", "xz", "txz", "lzma", "dmg"].contains(fileExtension) else {
55+
guard ["zip", "tar", "gz", "tgz", "bz2", "tbz", "xz", "txz", "lzma", "dmg", "aar", "yaa"].contains(fileExtension) else {
5656
continue
5757
}
5858

0 commit comments

Comments
 (0)