### Shell Compilation and Execution Source: https://github.com/packagesdev/packages/blob/master/RegexKitLite-1.2/RegexKitLite.html This transcript shows the commands to compile and run the Objective-C example, demonstrating the output of the match enumerator. ```shell shell% cd examples shell% gcc -I.. -g -o main main.m RKLMatchEnumerator.m ../RegexKitLite.m -framework Foundation -licucore shell% ./main 2008-03-21 15:56:17.469 main[44050:807] searchString: 'one two four ' 2008-03-21 15:56:17.520 main[44050:807] regexString : '(?m)^.*$' 2008-03-21 15:56:17.575 main[44050:807] 1: 3 'one' 2008-03-21 15:56:17.580 main[44050:807] 2: 3 'two' 2008-03-21 15:56:17.584 main[44050:807] 3: 0 '' 2008-03-21 15:56:17.590 main[44050:807] 4: 4 'four' shell% ▌ ``` -------------------------------- ### Define OS and Disk Space Installation Requirements Source: https://context7.com/packagesdev/packages/llms.txt Configure OS version and disk space requirements for installer pre-flight checks. Localized failure messages can be attached. ```objc #import "PKGRequirement.h" #import "PKGRequirementFailureMessage.h" // ── OS version requirement ──────────────────────────────────────────────────── PKGRequirement *osReq = [[PKGRequirement alloc] init]; osReq.enabled = YES; osReq.name = @"OS Version Check"; osReq.identifier = @"fr.whitebox.requirements.os"; osReq.type = PKGRequirementTypeInstallation; osReq.failureBehavior = PKGRequirementOnFailureBehaviorInstallationStop; // Plug in settings for the OS requirement plugin osReq.settingsRepresentation = @{ @"OS_TARGET_DISK" : @(PKGRequirementOSTargetStartupDisk), @"OS_DISTRIBUTION" : @(PKGRequirementOSDistributionClient), @"OS_MINIMUM_VERSION": @(101500), // 10.15 Catalina @"OS_MAXIMUM_VERSION": @(0) // no upper bound }; // Localized failure messages PKGRequirementFailureMessage *msg = [[PKGRequirementFailureMessage alloc] init]; msg.messageTitle = @"Unsupported macOS Version"; msg.messageDescription = @"This installer requires macOS 10.15 or later."; osReq.messages[@"en"] = [msg representation]; // ── Disk space requirement ──────────────────────────────────────────────────── PKGRequirement *diskReq = [[PKGRequirement alloc] init]; diskReq.enabled = YES; diskReq.identifier = @"fr.whitebox.requirements.diskspace"; diskReq.type = PKGRequirementTypeTarget; diskReq.failureBehavior = PKGRequirementOnFailureBehaviorInstallationWarning; diskReq.settingsRepresentation = @{ @"DISK_SPACE_MINIMUM_SIZE_VALUE": @(2), @"DISK_SPACE_MINIMUM_SIZE_UNIT" : @(PKGRequirementDiskSpaceSizeUnitGB) }; // Attach requirements to a distribution project PKGDistributionProjectRequirementsAndResources *rr = dist.requirementsAndResources; [rr.requirements addObject:osReq]; [rr.requirements addObject:diskReq]; ``` -------------------------------- ### Manage .pkgproj Files with packagesutil (Get) Source: https://context7.com/packagesdev/packages/llms.txt Use `packagesutil` with the `get` verb to retrieve project-level and package-level properties from `.pkgproj` files without opening the GUI. This is useful for scripting and automation. ```sh packagesutil --file MyApp.pkgproj get project name ``` ```sh packagesutil --file MyApp.pkgproj get project build-folder ``` ```sh packagesutil --file MyApp.pkgproj get project build-format ``` ```sh packagesutil --file MyApp.pkgproj get package identifier ``` ```sh packagesutil --file MyApp.pkgproj get package version ``` ```sh packagesutil --file MyApp.pkgproj get package post-installation-behavior ``` ```sh packagesutil --file MyApp.pkgproj get package pre-installation-script ``` -------------------------------- ### PKGPackageScriptsAndResources Source: https://context7.com/packagesdev/packages/llms.txt Associates pre-installation and post-installation scripts with a package, along with any bundled resources needed at install time. ```APIDOC ## Pre/Post Install Scripts PKGPackageScriptsAndResources *scripts = [[PKGPackageScriptsAndResources alloc] init]; // Pre-install script (absolute path) scripts.preInstallationScriptPath = [PKGFilePath filePathWithAbsolutePath:@"/scripts/preinstall.sh"]; // Post-install script (relative to project) scripts.postInstallationScriptPath = [PKGFilePath filePathWithString:@"scripts/postinstall.sh" type:PKGFilePathTypeRelativeToProject]; // Attach to a component PKGPackageComponent *comp = [PKGPackageComponent projectComponent]; comp.scriptsAndResources = scripts; // Inspect NSLog(@"Pre: %@", comp.scriptsAndResources.preInstallationScriptPath.string); NSLog(@"Post: %@", comp.scriptsAndResources.postInstallationScriptPath.string); ``` -------------------------------- ### Create PKGFileItem for New Folder Source: https://context7.com/packagesdev/packages/llms.txt Use PKGFileItem to represent a new folder created during installation. Specify its name, owner (uid), group (gid), and permissions. ```objc #import "PKGFileItem.h" #import "PKGFilePath.h" // ── New folder created by the installer ────────────────────────────────────── PKGFileItem *appFolder = [PKGFileItem newFolderWithName:@"MyApp" uid:0 // root gid:80 // admin permissions:0755]; ``` -------------------------------- ### PKGFileItem Source: https://context7.com/packagesdev/packages/llms.txt Represents a single entry (file, folder template, or new folder) in the installer payload hierarchy, along with its ownership and permissions. ```APIDOC ## Model API: `PKGFileItem` — Payload File System Entries Represents a single entry (file, folder template, or new folder) in the installer payload hierarchy, along with its ownership and permissions. ```objc #import "PKGFileItem.h" #import "PKGFilePath.h" // ── New folder created by the installer ────────────────────────────────────── PKGFileItem *appFolder = [PKGFileItem newFolderWithName:@"MyApp" uid:0 // root gid:80 // admin permissions:0755]; // ── Folder template (mirrors a pre-existing directory) ─────────────────────── PKGFileItem *libFolder = [PKGFileItem folderTemplateWithName:@"Application Support" uid:0 gid:80 permissions:0755]; // ── File system item sourced from disk ─────────────────────────────────────── PKGFilePath *srcPath = [PKGFilePath filePathWithAbsolutePath:@"/build/MyApp.app"]; PKGFileItem *appItem = [PKGFileItem fileSystemItemWithFilePath:srcPath uid:0 gid:80 permissions:0755]; // ── Elastic folder (auto-expands during installation) ──────────────────────── PKGFileItem *elastic = [PKGFileItem newElasticFolderWithName:@"Plugins" uid:0 gid:80 permissions:0755]; // Payload file name (name inside the installed package) appItem.payloadFileName = @"MyApplication.app"; // Inspect type NSLog(@"Is file system item: %d", appItem.type == PKGFileItemTypeFileSystemItem); // → 1 ``` ``` -------------------------------- ### PKGPackageSettings - Per-Package Metadata Source: https://context7.com/packagesdev/packages/llms.txt Explains how to configure metadata for a single package component, including basic information, installation behavior, authorization, and payload options. ```APIDOC ## Basic metadata settings.name = @"MyApplication"; settings.identifier = @"com.acme.myapp"; settings.version = @"3.2.1"; ## Post-install behavior settings.conclusionAction = PKGPackageConclusionActionRequireRestart; ## Authorization settings.authenticationMode = PKGPackageAuthenticationRoot; ## Payload options settings.relocatable = NO; settings.overwriteDirectoryPermissions = YES; settings.followSymbolicLinks = NO; settings.useHFSPlusCompression = YES; ## Package location (embedded in distribution) settings.locationType = PKGPackageLocationEmbedded; ## Package location (external HTTP URL) settings.locationType = PKGPackageLocationHTTPSURL; settings.locationURL = @"https://cdn.acme.com/packages/myapp-3.2.1.pkg"; ## Derived helpers NSString *scheme = [settings locationScheme]; // → @"https" NSString *path = [settings locationPath]; // → @"//cdn.acme.com/packages/myapp-3.2.1.pkg" ## Serialize to / from representation NSMutableDictionary *rep = [settings representation]; PKGPackageSettings *restored = [[PKGPackageSettings alloc] initWithRepresentation:rep error:nil]; NSLog(@"%@ %@", restored.identifier, restored.version); // → com.acme.myapp 3.2.1 ``` -------------------------------- ### PKGDistributionProject Source: https://context7.com/packagesdev/packages/llms.txt Manages a collection of PKGPackageComponent objects along with presentation settings and installation requirements. ```APIDOC ## Load an existing distribution project NSError *error = nil; PKGDistributionProject *dist = (PKGDistributionProject *) [PKGProject projectWithContentsOfFile:@"/Projects/Suite.pkgproj" error:&error]; PKGDistributionProjectSettings *settings = (PKGDistributionProjectSettings *)dist.settings; settings.buildFormat = PKGProjectBuildFormatFlat; settings.name = @"ACME Suite Installer"; ## Iterate package components for (PKGPackageComponent *comp in dist.packageComponents) { NSLog(@"UUID: %@ type: %lu name: %@", comp.UUID, (unsigned long)comp.type, comp.packageSettings.name); } ## Look up a component PKGPackageComponent *comp = [dist packageComponentWithIdentifier:@"com.acme.framework"]; NSLog(@"Found: %@", comp.packageSettings.name); ## Add a new project component PKGPackageComponent *newComp = [PKGPackageComponent projectComponent]; newComp.packageSettings.name = @"ACME Helper"; newComp.packageSettings.identifier = @"com.acme.helper"; newComp.packageSettings.version = @"1.0.0"; [dist.packageComponents addObject:newComp]; ## Check whether it is flat NSLog(@"Flat: %d", dist.isFlat); // → 1 ## Save [dist writeToFile:@"/Projects/Suite.pkgproj" atomically:YES]; ``` -------------------------------- ### Configure Package Payload Source: https://context7.com/packagesdev/packages/llms.txt Create and configure package payloads. Use `PKGPackagePayload.emptyPayload` for a new payload or `initWithDefaultHierarchy:error:` to initialize with a structure. The install location can also be extracted from raw XML data. ```objc #import "PKGPackagePayload.h" #import "PKGPayloadTree.h" // ── Create an empty payload ─────────────────────────────────────────────────── PKGPackagePayload *payload = [PKGPackagePayload emptyPayload]; payload.defaultInstallLocation = @"/"; payload.type = PKGPayloadInternal; payload.splitForksIfNeeded = NO; payload.preserveExtendedAttributes = YES; payload.hiddenFolderTemplatesIncluded = YES; payload.treatMissingPayloadFilesAsWarnings = NO; // ── Create with a default hierarchy ───────────────────────────────────────── NSDictionary *defaultHierarchy = @{ @"PATH": @"Applications", @"PATH_TYPE": @0, @"TYPE": @1, @"GID": @80, @"UID": @0, @"PERMISSIONS": @493, @"CHILDREN": @[] }; NSError *err = nil; PKGPackagePayload *withHierarchy = [[PKGPackagePayload alloc] initWithDefaultHierarchy:defaultHierarchy error:&err]; // ── Extract install location from raw XML data ─────────────────────────────── NSData *packageInfoXML = /* raw PackageInfo XML bytes from an existing .pkg */ nil; NSString *loc = [PKGPackagePayload installLocationWithXMLData:packageInfoXML]; NSLog(@"Install location: %@", loc); // → / // ── Attach to a package component ──────────────────────────────────────────── PKGPackageComponent *comp = [PKGPackageComponent projectComponent]; comp.payload = payload; ``` -------------------------------- ### PKGPackagePayload Source: https://context7.com/packagesdev/packages/llms.txt Configures the payload root tree, default install location, and various payload-level options for a single package. ```APIDOC ## Create an empty payload PKGPackagePayload *payload = [PKGPackagePayload emptyPayload]; payload.defaultInstallLocation = @"/"; payload.type = PKGPayloadInternal; payload.splitForksIfNeeded = NO; payload.preserveExtendedAttributes = YES; payload.hiddenFolderTemplatesIncluded = YES; payload.treatMissingPayloadFilesAsWarnings = NO; ## Create with a default hierarchy NSDictionary *defaultHierarchy = @{ @"PATH": @"Applications", @"PATH_TYPE": @0, @"TYPE": @1, @"GID": @80, @"UID": @0, @"PERMISSIONS": @493, @"CHILDREN": @[] }; NSError *err = nil; PKGPackagePayload *withHierarchy = [[PKGPackagePayload alloc] initWithDefaultHierarchy:defaultHierarchy error:&err]; ## Extract install location from raw XML data NSData *packageInfoXML = /* raw PackageInfo XML bytes from an existing .pkg */ nil; NSString *loc = [PKGPackagePayload installLocationWithXMLData:packageInfoXML]; NSLog(@"Install location: %@", loc); // → / ## Attach to a package component PKGPackageComponent *comp = [PKGPackageComponent projectComponent]; comp.payload = payload; ``` -------------------------------- ### Execute App-Only Build Source: https://context7.com/packagesdev/packages/llms.txt Use the `build_app.sh` script to build only the application and its package, omitting the DMG creation step. This is useful for development or when only the installer package is needed. ```sh cd /path/to/packages-repo/distribution ./build_app.sh # Same as build.sh but stops after producing Packages.pkg ``` -------------------------------- ### Create PKGFileItem for Elastic Folder Source: https://context7.com/packagesdev/packages/llms.txt Use PKGFileItem to represent an elastic folder that automatically expands during installation. Specify its name, owner (uid), group (gid), and permissions. ```objc // ── Elastic folder (auto-expands during installation) ──────────────────────── PKGFileItem *elastic = [PKGFileItem newElasticFolderWithName:@"Plugins" uid:0 gid:80 permissions:0755]; ``` -------------------------------- ### PKGCertificatesUtilities - Code-Signing Identity Lookup Source: https://context7.com/packagesdev/packages/llms.txt Queries the system keychain for available Developer ID Installer certificates and resolves signing identities for use with `packagesbuild`. ```APIDOC ## PKGCertificatesUtilities ### Description Queries the system keychain for available Developer ID Installer certificates and resolves signing identities for use with `packagesbuild`. ### Methods #### `availableIdentities` Lists all available signing identities. **Return Value** An array of strings, where each string is the name of an available signing identity. **Usage** ```objc NSArray *identities = [PKGCertificatesUtilities availableIdentities]; for (NSString *name in identities) { NSLog(@" %@", name); } // → Developer ID Installer: ACME Corp (XXXXXXXXXX) ``` #### `identityWithName:atPath:options:error:` Looks up a specific identity in the system keychain. **Parameters** - **name** (NSString *) - The name of the identity to look up. - **path** (NSString *) - The path to the keychain file. Use `PKGLoginKeychainPath` for the login keychain. - **options** (PKGCertificateSearchOptions) - Options for searching certificates, e.g., `PKGCertificateSearchNonExpired`. - **error** (OSStatus *) - A pointer to an `OSStatus` variable to store any error code. **Return Value** A `SecIdentityRef` representing the found identity, or `NULL` if an error occurred. **Usage** ```objc OSStatus status; SecIdentityRef identity = [PKGCertificatesUtilities identityWithName:@"Developer ID Installer: ACME Corp" atPath:PKGLoginKeychainPath options:PKGCertificateSearchNonExpired error:&status]; if (identity) { NSLog(@"Identity found"); CFRelease(identity); } else { NSLog(@"Error: %d", (int)status); } ``` #### `identityWithName:atPath:error:` Looks up a specific identity using an error code enum for error handling. **Parameters** - **name** (NSString *) - The name of the identity to look up. - **path** (NSString *) - The path to the keychain file. - **error** (PKGCertificateErrorCode *) - A pointer to a `PKGCertificateErrorCode` variable to store the error. **Return Value** A `SecIdentityRef` representing the found identity, or `NULL` if an error occurred. **Usage** ```objc PKGCertificateErrorCode errCode; SecIdentityRef id2 = [PKGCertificatesUtilities identityWithName:@"Developer ID Installer: ACME Corp" atPath:@"/Users/ci/Library/Keychains/CI.keychain" error:&errCode]; if (!id2) { switch (errCode) { case PKGCertificateErrorMissingCertificate: NSLog(@"Certificate not found"); break; case PKGCertificateErrorExpiredCertificate: NSLog(@"Certificate expired"); break; case PKGCertificateErrorMissingPrivateKey: NSLog(@"Private key not found"); break; } } ``` #### `copyOfCertificateWithName:isExpired:` Checks whether a certificate is expired. **Parameters** - **name** (NSString *) - The name of the certificate to check. - **expired** (BOOL *) - A pointer to a boolean variable that will be set to `YES` if the certificate is expired, `NO` otherwise. **Return Value** A `SecCertificateRef` representing the certificate, or `NULL` if the certificate is not found. **Usage** ```objc BOOL expired = NO; SecCertificateRef cert = [PKGCertificatesUtilities copyOfCertificateWithName:@"Developer ID Installer: ACME Corp" isExpired:&expired]; NSLog(@"Expired: %d", expired); if (cert) CFRelease(cert); ``` ``` -------------------------------- ### List Available Signing Identities Source: https://context7.com/packagesdev/packages/llms.txt Queries the system keychain for all available Developer ID Installer certificates. This is useful for identifying potential signing identities before attempting to use them. ```objc #import "PKGCertificatesUtilities.h" // ── List all available signing identities ──────────────────────────────────── NSArray *identities = [PKGCertificatesUtilities availableIdentities]; for (NSString *name in identities) { NSLog(@" %@", name); } // → Developer ID Installer: ACME Corp (XXXXXXXXXX) ``` -------------------------------- ### Configure Regex Filter for PKGFileFilter Source: https://context7.com/packagesdev/packages/llms.txt Use this to create a regex-based file filter, for example, to exclude version control directories. Ensure the predicate is configured with `regularExpression = YES` and the desired pattern. Add the configured filter to the project's settings. ```objc // ── Regex filter (exclude .git directories) ─────────────────────────────────── PKGFilePredicate *gitPred = [[PKGFilePredicate alloc] init]; gitPred.regularExpression = YES; gitPred.pattern = @"^\\.git$"; gitPred.fileType = PKGFileSystemTypeFolder; PKGFileFilter *gitFilter = [[PKGFileFilter alloc] init]; gitFilter.enabled = YES; gitFilter.predicate = gitPred; ``` -------------------------------- ### Get String from First Regex Match Source: https://github.com/packagesdev/packages/blob/master/RegexKitLite-1.2/RegexKitLite.html Returns a string created from the characters of the receiver that fall within the range of the first match of the given regular expression. ```objective-c - (NSString *)stringByMatching:(NSString *)regexString; ``` -------------------------------- ### Package Project Configuration (.pkgproj) Source: https://context7.com/packagesdev/packages/llms.txt Defines the structure of a .pkgproj file, which is an Apple Property List XML document used for configuring package projects. It includes settings for the project, individual packages, file installations, and scripts. ```xml PROJECT PROJECT_SETTINGS NAME My Application Installer BUILD_FORMAT 0 BUILD_PATH PATH build PATH_TYPE 1 REFERENCE_FOLDER_PATH CERTIFICATE PACKAGES UUID A1B2C3D4-... TYPE 0 PACKAGE_SETTINGS NAME My Application IDENTIFIER com.acme.myapp VERSION 3.2.1 CONCLUSION_ACTION 0 LOCATION_TYPE 0 AUTHENTICATION 1 RELOCATABLE HFS_COMPRESSION PACKAGE_FILES DEFAULT_INSTALL_LOCATION / HIERARCHY TYPE 0 PATH / PATH_TYPE 0 UID 0 GID 0 PERMISSIONS 509 CHILDREN TYPE 1 PATH Applications PATH_TYPE 0 UID 0 GID 80 PERMISSIONS 509 CHILDREN TYPE 3 PATH build/MyApp.app PATH_TYPE 1 UID 0 GID 80 PERMISSIONS 493 SCRIPTS_AND_RESOURCES PRE_INSTALLATION_SCRIPT PATH scripts/preinstall.sh PATH_TYPE 1 POST_INSTALLATION_SCRIPT PATH scripts/postinstall.sh PATH_TYPE 1 ``` -------------------------------- ### Demonstration of Match Enumerator Source: https://github.com/packagesdev/packages/blob/master/RegexKitLite-1.2/RegexKitLite.html This example demonstrates using the match enumerator to find all lines in a string. It utilizes a regular expression with the multiline option enabled to match entire lines, including empty ones. ```objective-c #import #import "RegexKitLite.h" #import "RKLMatchEnumerator.h" int main(int argc, char *argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSString *searchString = @"one\ntwo\n\nfour\n"; NSEnumerator *matchEnumerator = NULL; NSString *regexString = @"(?m)^.*$"; NSLog(@"searchString: '%@'", searchString); NSLog(@"regexString : '%@'", regexString); matchEnumerator = [searchString matchEnumeratorWithRegex:regexString]; NSUInteger line = 0; NSString *matchedString = NULL; while((matchedString = [matchEnumerator nextObject]) != NULL) { NSLog(@"%d: %d '%@'", ++line, [matchedString length], matchedString); } [pool release]; return(0); } ``` -------------------------------- ### Basic RegexKit Lite Usage in Objective-C Source: https://github.com/packagesdev/packages/blob/master/RegexKitLite-1.2/RegexKitLite.html An example of using RegexKit Lite to match a regular expression against a string and capture a specific group. This code snippet is intended to be compiled and run from the shell. ```objective-c #import #import #import "RegexKitLite.h" int main(int argc, char *argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // Copyright COPYRIGHT_SIGN APPROXIMATELY_EQUAL_TO 2008 // Copyright \u00a9 \u2245 2008 char *utf8CString = "Copyright \xC2\xA9 \xE2\x89\x85 2008"; NSString *regexString = @"Copyright (.*) (\\d+)"; NSString *subjectString = [NSString stringWithUTF8String:utf8CString]; NSString *matchedString = [subjectString stringByMatching:regexString capture:1]; NSLog(@"subject: \"%@\"", subjectString); NSLog(@"matched: \"%@\"", matchedString); [pool release]; return(0); } ``` -------------------------------- ### Get Capture Count for Regex with Options and Error Handling Source: https://github.com/packagesdev/packages/blob/master/RegexKitLite-1.2/RegexKitLite.html Returns the number of captures a regular expression contains, with options for matching and error handling. Returns -1 if an error occurs. ```objective-c + (NSInteger)captureCountForRegex:(NSString *)regexString options:(RKLRegexOptions)options error:(NSError **)error; ``` -------------------------------- ### Get String from Regex Match with Options, Range, and Capture Source: https://github.com/packagesdev/packages/blob/master/RegexKitLite-1.2/RegexKitLite.html Returns a string created from the characters of the receiver that fall within the range of a specific capture group for the first match of the given regular expression, using provided options and searching within a specified range. ```objective-c - (NSString *)stringByMatching:(NSString *)regexString options:(RKLRegexOptions)options inRange:(NSRange)range capture:(NSInteger)capture error:(NSError **)error; ``` -------------------------------- ### Programmatically Execute a Build Order Source: https://context7.com/packagesdev/packages/llms.txt Initiate a build process by submitting a PKGBuildOrder to the packages_dispatcher via XPC. Register for build events and handle completion or errors. ```objc #import "PKGBuildOrderManager.h" #import "PKGBuildOrder.h" #import "PKGBuildNotificationCenter.h" #import "PKGBuildStep+Constants.h" // ── Assemble external settings ──────────────────────────────────────────────── NSDictionary *externalSettings = @{ PKGBuildOrderExternalSettingsBuildFolderKey : @"/Users/ci/build", PKGBuildOrderExternalSettingsSigningIdentityKey: @"Developer ID Installer: ACME (XXXXXXXXXX)", PKGBuildOrderExternalSettingsEmbedTimestamp : @YES, PKGBuildOrderExternalSettingsUserDefinedSettingsKey: @{ @"PRODUCT_VERSION": @"3.2.1", @"COPYRIGHT_YEAR" : @"2026" } }; // ── Create build order ──────────────────────────────────────────────────────── PKGBuildOrder *order = [[PKGBuildOrder alloc] init]; order.projectPath = @"/Projects/MyApp.pkgproj"; order.buildOptions = 0; // PKGBuildOptionDebugBuild | PKGBuildOptionLaunchAfterBuild order.externalSettings = externalSettings; // ── Execute ─────────────────────────────────────────────────────────────────── [[PKGBuildOrderManager defaultManager] executeBuildOrder:order setupHandler:^(PKGBuildNotificationCenter *center) { // Register for step events [[NSNotificationCenter defaultCenter] addObserverForName:PKGBuildEventNotification object:center queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *n) { NSString *path = n.userInfo[PKGBuildStepPathKey]; NSNumber *state = n.userInfo[PKGBuildStateKey]; NSLog(@"[%%@] step: %%@", state.unsignedIntegerValue == PKGBuildStepStateSuccess ? @"OK" : @" ", path); }]; } completionHandler:^(PKGBuildResult result) { switch (result) { case PKGBuildResultSuccessful: NSLog(@"Build succeeded"); break; case PKGBuildResultAborted: NSLog(@"Build aborted"); break; case PKGBuildResultBuildOrderExecutionAgentDidExit: NSLog(@"Builder agent exited unexpectedly"); break; } exit(result == PKGBuildResultSuccessful ? 0 : 1); } communicationErrorHandler:^(NSError *error) { NSLog(@"XPC error: %%@", error); exit(2); }]; [[NSRunLoop mainRunLoop] run]; ``` -------------------------------- ### PKGProject - Loading and Saving Project Files Source: https://context7.com/packagesdev/packages/llms.txt Demonstrates how to load project files from disk or URL and save them back. It also shows how to determine the project type after loading. ```APIDOC ## Load a project from disk (type is determined automatically) NSError *error = nil; PKGProject *project = [PKGProject projectWithContentsOfFile:@"/Projects/MyApp.pkgproj" error:&error]; if (!project) { NSLog(@"Load failed: %@", error.localizedDescription); return; } // Determine project type if (project.type == PKGProjectTypeDistribution) { PKGDistributionProject *dist = (PKGDistributionProject *)project; NSLog(@"Distribution project with %lu packages", dist.packageComponents.count); } else { PKGPackageProject *pkg = (PKGPackageProject *)project; NSLog(@"Package: %@ version: %@", pkg.packageSettings.name, pkg.packageSettings.version); } ## Load from URL NSURL *url = [NSURL fileURLWithPath:@"/Projects/Distribution.pkgproj"]; PKGDistributionProject *dist = (PKGDistributionProject *) [PKGProject projectWithContentsOfURL:url error:&error]; ## Save back to disk dist.settings.name = @"My Application Installer"; BOOL ok = [dist writeToFile:@"/Projects/Distribution.pkgproj" atomically:YES]; NSLog(@"Save %@", ok ? @"succeeded" : @"failed"); ``` -------------------------------- ### Create and Resolve PKGFilePath References Source: https://context7.com/packagesdev/packages/llms.txt Demonstrates creating different types of PKGFilePath (absolute, relative to project, named) and resolving them to absolute paths using a PKGFilePathConverter. Also shows converting absolute paths back to typed file paths. ```objc #import "PKGFilePath.h" #import "PKGFilePathConverter.h" // ── Create paths ───────────────────────────────────────────────────────────── PKGFilePath *absolute = [PKGFilePath filePathWithAbsolutePath:@"/scripts/preinstall.sh"]; PKGFilePath *relative = [PKGFilePath filePathWithString:@"scripts/preinstall.sh" type:PKGFilePathTypeRelativeToProject]; PKGFilePath *named = [PKGFilePath filePathWithName:@"preinstall.sh"]; NSLog(@"%d", (int)absolute.type); // 0 (PKGFilePathTypeAbsolute) NSLog(@"%@", relative.lastPathComponent); // → preinstall.sh // ── Resolve to absolute path using a converter ──────────────────────────────── PKGFilePathConverter *converter = [[PKGFilePathConverter alloc] init]; converter.referenceProjectPath = @"/Users/ci/Projects/MyApp.pkgproj"; converter.referenceFolderPath = @"/Volumes/BuildServer/sources"; NSString *abs = [converter absolutePathForFilePath:relative]; // → /Users/ci/Projects/scripts/preinstall.sh // ── Convert an absolute path back to a typed file path ─────────────────────── PKGFilePath *fp = [converter filePathForAbsolutePath:@"/Volumes/BuildServer/sources/Assets/icon.png" type:PKGFilePathTypeRelativeToReferenceFolder]; NSLog(@"%@", fp.string); // → Assets/icon.png // ── Shift type in-place ─────────────────────────────────────────────────────── [converter shiftTypeOfFilePath:fp toType:PKGFilePathTypeAbsolute]; NSLog(@"%@", fp.string); // → /Volumes/BuildServer/sources/Assets/icon.png ``` -------------------------------- ### Load and Save PKGProject Files Source: https://context7.com/packagesdev/packages/llms.txt Demonstrates loading a project from disk or URL and saving it back. The project type is determined automatically upon loading. ```objc #import "PKGProject.h" #import "PKGPackageProject.h" #import "PKGDistributionProject.h" // ── Load a project from disk (type is determined automatically) ────────────── NSError *error = nil; PKGProject *project = [PKGProject projectWithContentsOfFile:@"/Projects/MyApp.pkgproj" error:&error]; if (!project) { NSLog(@"Load failed: %@", error.localizedDescription); return; } // Determine project type if (project.type == PKGProjectTypeDistribution) { PKGDistributionProject *dist = (PKGDistributionProject *)project; NSLog(@"Distribution project with %lu packages", dist.packageComponents.count); } else { PKGPackageProject *pkg = (PKGPackageProject *)project; NSLog(@"Package: %@ version: %@", pkg.packageSettings.name, pkg.packageSettings.version); } // ── Load from URL ──────────────────────────────────────────────────────────── NSURL *url = [NSURL fileURLWithPath:@"/Projects/Distribution.pkgproj"]; PKGDistributionProject *dist = (PKGDistributionProject *) [PKGProject projectWithContentsOfURL:url error:&error]; // ── Save back to disk ──────────────────────────────────────────────────────── dist.settings.name = @"My Application Installer"; BOOL ok = [dist writeToFile:@"/Projects/Distribution.pkgproj" atomically:YES]; NSLog(@"Save %@", ok ? @"succeeded" : @"failed"); ``` -------------------------------- ### Add and Check File Filters in Project Settings Source: https://context7.com/packagesdev/packages/llms.txt Demonstrates how to add configured file filters to project settings and perform a convenience check to see if a file should be filtered. ```objc // ── Add filters to project settings ────────────────────────────────────────── [project.settings.filesFilters addObject:filter]; [project.settings.filesFilters addObject:gitFilter]; // ── Convenience check via project settings ──────────────────────────────────── BOOL excluded = [project.settings shouldFilterFileNamed:@".DS_Store" ofType:PKGFileSystemTypeFile]; NSLog(@"Excluded: %d", excluded); // → 1 ``` -------------------------------- ### Get Range of Regex Match Source: https://github.com/packagesdev/packages/blob/master/RegexKitLite-1.2/RegexKitLite.html Returns the range for the first match of the given regular expression in the receiver string. ```objective-c - (NSRange)rangeOfRegex:(NSString *)regexString; ``` -------------------------------- ### Manage Package Scripts and Resources Source: https://context7.com/packagesdev/packages/llms.txt Associate pre- and post-installation scripts with a package component. Scripts can be specified using absolute paths or paths relative to the project. The paths are managed using `PKGFilePath` objects. ```objc #import "PKGPackageScriptsAndResources.h" #import "PKGFilePath.h" PKGPackageScriptsAndResources *scripts = [[PKGPackageScriptsAndResources alloc] init]; // Pre-install script (absolute path) scripts.preInstallationScriptPath = [PKGFilePath filePathWithAbsolutePath:@"/scripts/preinstall.sh"]; // Post-install script (relative to project) scripts.postInstallationScriptPath = [PKGFilePath filePathWithString:@"scripts/postinstall.sh" type:PKGFilePathTypeRelativeToProject]; // Attach to a component PKGPackageComponent *comp = [PKGPackageComponent projectComponent]; comp.scriptsAndResources = scripts; // Inspect NSLog(@"Pre: %@", comp.scriptsAndResources.preInstallationScriptPath.string); NSLog(@"Post: %@", comp.scriptsAndResources.postInstallationScriptPath.string); ``` -------------------------------- ### Compiling and Running RegexKit Lite from Shell Source: https://github.com/packagesdev/packages/blob/master/RegexKitLite-1.2/RegexKitLite.html Demonstrates how to compile and run a simple Objective-C program using RegexKit Lite from the command line. Ensure you link against the Foundation framework and the ICU library. ```shell shell% cd examples shell% gcc -g -I.. -o link_example link_example.m ../RegexKitLite.m -framework Foundation -licucore ``` ```shell shell% ./link_example ``` -------------------------------- ### Manage Distribution Projects Source: https://context7.com/packagesdev/packages/llms.txt Load, modify, and save distribution projects. Use `PKGProject` to load an existing project, access its settings and package components, and add new components. Ensure to handle potential errors during loading. ```objc #import "PKGDistributionProject.h" #import "PKGPackageComponent.h" #import "PKGDistributionProjectSettings.h" // ── Load an existing distribution project ──────────────────────────────────── NSError *error = nil; PKGDistributionProject *dist = (PKGDistributionProject *) [PKGProject projectWithContentsOfFile:@"/Projects/Suite.pkgproj" error:&error]; PKGDistributionProjectSettings *settings = (PKGDistributionProjectSettings *)dist.settings; settings.buildFormat = PKGProjectBuildFormatFlat; settings.name = @"ACME Suite Installer"; // ── Iterate package components ─────────────────────────────────────────────── for (PKGPackageComponent *comp in dist.packageComponents) { NSLog(@"UUID: %@ type: %lu name: %@", comp.UUID, (unsigned long)comp.type, comp.packageSettings.name); } // ── Look up a component ────────────────────────────────────────────────────── PKGPackageComponent *comp = [dist packageComponentWithIdentifier:@"com.acme.framework"]; NSLog(@"Found: %@", comp.packageSettings.name); // ── Add a new project component ────────────────────────────────────────────── PKGPackageComponent *newComp = [PKGPackageComponent projectComponent]; newComp.packageSettings.name = @"ACME Helper"; newComp.packageSettings.identifier = @"com.acme.helper"; newComp.packageSettings.version = @"1.0.0"; [dist.packageComponents addObject:newComp]; // ── Check whether it is flat ───────────────────────────────────────────────── NSLog(@"Flat: %d", dist.isFlat); // → 1 // ── Save ───────────────────────────────────────────────────────────────────── [dist writeToFile:@"/Projects/Suite.pkgproj" atomically:YES]; ``` -------------------------------- ### Configure Simple Glob Filter for PKGFileFilter Source: https://context7.com/packagesdev/packages/llms.txt Use this to create a simple glob-based file filter. Ensure the predicate is configured with `regularExpression = NO` and the desired pattern. Add the configured filter to the project's settings. ```objc #import "PKGFileFilter.h" // ── Simple glob filter (disable .DS_Store) ──────────────────────────────────── PKGFilePredicate *pred = [[PKGFilePredicate alloc] init]; pred.regularExpression = NO; pred.pattern = @".DS_Store"; pred.fileType = PKGFileSystemTypeFile; PKGFileFilter *filter = [[PKGFileFilter alloc] init]; filter.enabled = YES; filter.predicate = pred; NSLog(@"%d", [filter matchesFileNamed:@".DS_Store" ofType:PKGFileSystemTypeFile]); // → 1 NSLog(@"%d", [filter matchesFileNamed:@"Info.plist" ofType:PKGFileSystemTypeFile]); // → 0 ``` -------------------------------- ### Get Range of Regex Match within Range Source: https://github.com/packagesdev/packages/blob/master/RegexKitLite-1.2/RegexKitLite.html Returns the range for the first match of the given regular expression within a specified range of the receiver string. ```objective-c - (NSRange)rangeOfRegex:(NSString *)regexString inRange:(NSRange)range; ``` -------------------------------- ### Get Range of Specific Capture in Regex Match Source: https://github.com/packagesdev/packages/blob/master/RegexKitLite-1.2/RegexKitLite.html Returns the range of a specific capture group for the first match of the given regular expression in the receiver string. ```objective-c - (NSRange)rangeOfRegex:(NSString *)regexString capture:(NSInteger)capture; ``` -------------------------------- ### Execute Full Distribution Build Source: https://context7.com/packagesdev/packages/llms.txt Run the `build.sh` script from the distribution directory to perform a full build including application, package, and DMG. This script manages the dependency order for sub-projects. ```sh cd /path/to/packages-repo/distribution ./build.sh # Builds: goldin → packagesutil → packagesbuild → packages_dispatcher → # packages_builder → all requirement plugins → all locator plugins → # Packages.app GUI → Packages.pkg → Packages.dmg ``` -------------------------------- ### Create PKGFileItem from File System Path Source: https://context7.com/packagesdev/packages/llms.txt Use PKGFileItem to represent a file system item sourced from disk. Provide the file path, owner (uid), group (gid), and permissions. ```objc // ── File system item sourced from disk ─────────────────────────────────────── PKGFilePath *srcPath = [PKGFilePath filePathWithAbsolutePath:@"/build/MyApp.app"]; PKGFileItem *appItem = [PKGFileItem fileSystemItemWithFilePath:srcPath uid:0 gid:80 permissions:0755]; ``` -------------------------------- ### Configure PKGPackageSettings Metadata Source: https://context7.com/packagesdev/packages/llms.txt Initializes and configures PKGPackageSettings for a single package, including basic metadata, post-install behavior, authorization, and payload options. Also shows serialization and deserialization. ```objc #import "PKGPackageSettings.h" PKGPackageSettings *settings = [[PKGPackageSettings alloc] init]; // Basic metadata settings.name = @"MyApplication"; settings.identifier = @"com.acme.myapp"; settings.version = @"3.2.1"; // Post-install behavior settings.conclusionAction = PKGPackageConclusionActionRequireRestart; // Authorization settings.authenticationMode = PKGPackageAuthenticationRoot; // Payload options settings.relocatable = NO; settings.overwriteDirectoryPermissions = YES; settings.followSymbolicLinks = NO; settings.useHFSPlusCompression = YES; // Package location (embedded in distribution) settings.locationType = PKGPackageLocationEmbedded; // Package location (external HTTP URL) settings.locationType = PKGPackageLocationHTTPSURL; settings.locationURL = @"https://cdn.acme.com/packages/myapp-3.2.1.pkg"; // Derived helpers NSString *scheme = [settings locationScheme]; // → @"https" NSString *path = [settings locationPath]; // → @"//cdn.acme.com/packages/myapp-3.2.1.pkg" // Serialize to / from representation NSMutableDictionary *rep = [settings representation]; PKGPackageSettings *restored = [[PKGPackageSettings alloc] initWithRepresentation:rep error:nil]; NSLog(@"%@ %@", restored.identifier, restored.version); // → com.acme.myapp 3.2.1 ``` -------------------------------- ### Get Capture Count for Regex Source: https://github.com/packagesdev/packages/blob/master/RegexKitLite-1.2/RegexKitLite.html Returns the number of captures a regular expression contains. Returns -1 if an error occurs, otherwise returns the number of captures (0 if none). ```objective-c + (NSInteger)captureCountForRegex:(NSString *)regexString; ``` -------------------------------- ### Create DMG Image Source: https://context7.com/packagesdev/packages/llms.txt Use `hdiutil` commands to convert a template DMG, attach it, copy the package, detach, and then convert to a compressed format. This process is handled by `build.sh`. ```sh hdiutil convert template.dmg -format UDRW -o build/diskimage_rw.dmg hdiutil attach build/diskimage_rw.dmg -mountpoint /Volumes/PackagesDMG cp build/Packages.pkg /Volumes/PackagesDMG/ hdiutil detach /Volumes/PackagesDMG hdiutil convert build/diskimage_rw.dmg -format UDZO -o "build/Packages 1.2.11.dmg" ```