Skip to content

Commit

Permalink
Add support for extracting Apple Archives (.aar files) (#2586)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
zorgiepoo authored Jun 19, 2024
1 parent 97a8f5a commit dd93743
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 10 deletions.
32 changes: 27 additions & 5 deletions Autoupdate/SUPipedUnarchiver.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ @implementation SUPipedUnarchiver
NSArray <NSString *> *extractTXZ = extractTGZ;

// Note: keep this list in sync with generate_appcast's unarchiveUpdates()
NSDictionary <NSString *, NSArray<NSString *> *> *extractCommandDictionary =
@{
NSMutableDictionary <NSString *, NSArray<NSString *> *> *extractCommandDictionary =
[@{
@".zip" : @[@"/usr/bin/ditto", @"-x",@"-k",@"-"],
@".tar" : @[@"/usr/bin/tar", @"-xC"],
@".tar.gz" : extractTGZ,
Expand All @@ -37,8 +37,28 @@ @implementation SUPipedUnarchiver
@".tbz" : extractTBZ,
@".tar.xz" : extractTXZ,
@".txz" : extractTXZ,
@".tar.lzma" : extractTXZ
};
@".tar.lzma" : extractTXZ,
} mutableCopy];

// At least the latest versions of 10.15 understand how to extract aar files
// Versions before 10.15 do not understand extracting newly created aar files
// Note encrypted aea files are supported in macOS 12 onwards, if we ever want to support those one day
if (@available(macOS 10.15.7, *)) {
NSString *appleArchiveCommand;
if (@available(macOS 11, *)) {
appleArchiveCommand = @"/usr/bin/aa";
} else {
// In 10.15 the utility was named yaa, which was later renamed to aar
appleArchiveCommand = @"/usr/bin/yaa";
}

NSArray <NSString *> *extractAppleArchive = @[appleArchiveCommand, @"extract", @"-d"];

[extractCommandDictionary addEntriesFromDictionary:@{
@".aar" : extractAppleArchive,
@".yaa" : extractAppleArchive,
}];
}

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

NSFileManager *fileManager = [NSFileManager defaultManager];

SULog(SULogLevelDefault, @"Extracting using '%@' '%@' < '%@' '%@'", command, [args componentsJoinedByString:@"' '"], _archivePath, destination);

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

if (expectedLength == 0) {
Expand Down
8 changes: 4 additions & 4 deletions Configurations/ConfigCommon.xcconfig
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,13 @@ SPARKLE_ICON_NAME = AppIcon
// If you change any of these version details, you must increase CURRENT_PROJECT_VERSION
// These variables must have a space after the '=' too
SPARKLE_VERSION_MAJOR = 2
SPARKLE_VERSION_MINOR = 6
SPARKLE_VERSION_PATCH = 3
SPARKLE_VERSION_MINOR = 7
SPARKLE_VERSION_PATCH = 0

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

MARKETING_VERSION = $(SPARKLE_VERSION_MAJOR).$(SPARKLE_VERSION_MINOR).$(SPARKLE_VERSION_PATCH)$(SPARKLE_VERSION_SUFFIX)
ALWAYS_SEARCH_USER_PATHS = NO
Expand Down
8 changes: 8 additions & 0 deletions Sparkle.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@
726F2CE61BC9C33D001971A4 /* SUOperatingSystem.m in Sources */ = {isa = PBXBuildFile; fileRef = 726F2CE41BC9C33D001971A4 /* SUOperatingSystem.m */; };
726F2CE81BC9C48F001971A4 /* SUConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 61299A5F09CA6EB100B7442F /* SUConstants.m */; };
726F2CEB1BC9C733001971A4 /* SUConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 61299A5F09CA6EB100B7442F /* SUConstants.m */; };
726FC0362C1E787A00177986 /* SparkleTestCodeSignApp.aar in Resources */ = {isa = PBXBuildFile; fileRef = 726FC0352C1E787A00177986 /* SparkleTestCodeSignApp.aar */; };
726FC0382C1E96AA00177986 /* SparkleTestCodeSignApp.enc.aar in Resources */ = {isa = PBXBuildFile; fileRef = 726FC0372C1E96AA00177986 /* SparkleTestCodeSignApp.enc.aar */; };
727DBAE526B5BBFD00111F0C /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = 727DBAE426B5BBFD00111F0C /* ArgumentParser */; };
727DBAE726B5C47800111F0C /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = 727DBAE626B5C47800111F0C /* ArgumentParser */; };
727DBAE926B5C48A00111F0C /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = 727DBAE826B5C48A00111F0C /* ArgumentParser */; };
Expand Down Expand Up @@ -1330,6 +1332,8 @@
726E4A361C89116000C57C6A /* SPUStandardUserDriverDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPUStandardUserDriverDelegate.h; sourceTree = "<group>"; };
726F2CE31BC9C33D001971A4 /* SUOperatingSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SUOperatingSystem.h; sourceTree = "<group>"; };
726F2CE41BC9C33D001971A4 /* SUOperatingSystem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SUOperatingSystem.m; sourceTree = "<group>"; };
726FC0352C1E787A00177986 /* SparkleTestCodeSignApp.aar */ = {isa = PBXFileReference; lastKnownFileType = file; path = SparkleTestCodeSignApp.aar; sourceTree = "<group>"; };
726FC0372C1E96AA00177986 /* SparkleTestCodeSignApp.enc.aar */ = {isa = PBXFileReference; lastKnownFileType = file; path = SparkleTestCodeSignApp.enc.aar; sourceTree = "<group>"; };
726FD2CB25F4BE5F00123BC6 /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = fa.lproj/MainMenu.strings; sourceTree = "<group>"; };
726FD2CC25F4BE5F00123BC6 /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = fa.lproj/Sparkle.strings; sourceTree = "<group>"; };
727F340A2605321D00020E85 /* SULog+NSError.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SULog+NSError.m"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1868,6 +1872,8 @@
729F7ECD27409076004592DC /* SparkleTestCodeSignApp_bad_extraneous.zip */,
72CCDEBD27421FD500B53718 /* SparkleTestCodeSignApp_bad_header.zip */,
F8761EB21ADC50EB000C9034 /* SparkleTestCodeSignApp.zip */,
726FC0352C1E787A00177986 /* SparkleTestCodeSignApp.aar */,
726FC0372C1E96AA00177986 /* SparkleTestCodeSignApp.enc.aar */,
72EB735E29BE981300FBCEE7 /* DevSignedApp.zip */,
72EB736029BEB36100FBCEE7 /* DevSignedAppVersion2.zip */,
14958C6C19AEBC610061B14F /* test-pubkey.pem */,
Expand Down Expand Up @@ -3191,10 +3197,12 @@
5AF6C74F1AEA46D10014A3AB /* test.pkg in Resources */,
72EB735F29BE981300FBCEE7 /* DevSignedApp.zip in Resources */,
72BC6C3D275027BF0083F14B /* SparkleTestCodeSign_apfs.dmg in Resources */,
726FC0382C1E96AA00177986 /* SparkleTestCodeSignApp.enc.aar in Resources */,
720DC50627A62CDC00DFF3EC /* testappcast_minimumAutoupdateVersionSkipping2.xml in Resources */,
5AD0FA7F1C73F2E2004BCEFF /* testappcast.xml in Resources */,
FA30773D24CBC295007BA37D /* testlocalizedreleasenotesappcast.xml in Resources */,
72CCDEBE27421FD500B53718 /* SparkleTestCodeSignApp_bad_header.zip in Resources */,
726FC0362C1E787A00177986 /* SparkleTestCodeSignApp.aar in Resources */,
722545B626805FF80036465C /* testappcast_info_updates.xml in Resources */,
7202DC9A269ABD3500737EC4 /* testappcast_phasedRollout.xml in Resources */,
5F1510A21C96E591006E1629 /* testnamespaces.xml in Resources */,
Expand Down
Binary file added Tests/Resources/SparkleTestCodeSignApp.aar
Binary file not shown.
Binary file added Tests/Resources/SparkleTestCodeSignApp.enc.aar
Binary file not shown.
14 changes: 14 additions & 0 deletions Tests/SUUnarchiverTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,18 @@ class SUUnarchiverTest: XCTestCase
self.unarchiveTestAppWithExtension("pkg", resourceName: "test", expectingInstallationType: SPUInstallationTypeApplication, expectingSuccess: false)
}
#endif

func testUnarchivingAppleArchive() {
self.unarchiveTestAppWithExtension("aar", resourceName: "SparkleTestCodeSignApp")
}

// If we support encrypted archives one day we will use "aea" file extension
// Password to this archive is whatisgoingonforeveroneday!
func testUnarchivingEncryptedAppleArchiveWithoutPassword() {
signal(SIGPIPE, SIG_IGN)

self.unarchiveTestAppWithExtension("enc.aar", resourceName: "SparkleTestCodeSignApp", expectingSuccess: false)

signal(SIGPIPE, SIG_DFL)
}
}
2 changes: 1 addition & 1 deletion generate_appcast/Unarchive.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func unarchiveUpdates(archivesSourceDir: URL, archivesDestDir: URL, disableNeste
let itemURL = archivesSourceDir.appendingPathComponent(item)
let fileExtension = itemURL.pathExtension
// Note: keep this list in sync with SUPipedUnarchiver
guard ["zip", "tar", "gz", "tgz", "bz2", "tbz", "xz", "txz", "lzma", "dmg"].contains(fileExtension) else {
guard ["zip", "tar", "gz", "tgz", "bz2", "tbz", "xz", "txz", "lzma", "dmg", "aar", "yaa"].contains(fileExtension) else {
continue
}

Expand Down

0 comments on commit dd93743

Please sign in to comment.