Skip to content

Conversation

@rodchristiansen
Copy link
Contributor

Pull Request that adds the remaining parts of the Swift implementation of munkipkg to bring it feature parity to the original Python version. Targets the same deployment requirements as Munki v7 (macOS 11+, Universal binaries).

  • Swift 5.5+ with Swift Package Manager (for async/await support)
  • Apple ArgumentParser for CLI interface
  • Yams library for YAML support
  • Async/await for improved performance
  • Native XMLDocument for plist handling

What was implemented

  • Project creation with template support (plist, json, yaml formats)
  • Package building from project directories
  • Package import for both flat and bundle package formats
  • BOM export for Git workflow integration
  • File permission synchronization using Bom.txt files
  • Support for payload-free packages and distribution-style packages
  • Completes the command-line interface matching Python version
  • Property List (.plist): Native XMLDocument integration
  • JSON (.json): Built-in encoding/decoding with proper type handling
  • YAML (.yaml/.yml): Full support via Yams library

Key Details per .swift file

buildinfo.swift - Configuration Handling

Implements comprehensive build configuration management supporting all three file formats (plist, json, yaml). Uses Swift's Codable protocol for type-safe serialization/deserialization with proper error handling. Includes automatic variable substitution (e.g., ${version} in package names) and validation of configuration options.

  • Native plist support via PropertyListEncoder/Decoder
  • JSON support via Swift's built-in JSONEncoder/Decoder
  • YAML support through Yams library integration
  • Public API design enables comprehensive unit testing
  • Type-safe enums for ownership, post-install actions, and compression options

munkipkg.swift - Main Application Logic

Implements the complete command-line interface and core workflows using Swift's ArgumentParser. Handles all primary operations: project creation, package building, package import, and BOM export. Uses async/await for external tool invocation (pkgbuild, pkgutil, lsbom).

  • error handling with specific exit codes
  • Async/await integration for tool execution
  • Package import with proper Payload directory handling (fixed conflict resolution)
  • Support for both flat and bundle package formats
  • Automatic build-info format detection and generation

cliutils.swift - CLI Execution Utilities

Added Swift async/await patterns, reducing the code by ~290 lines while maintaining functionality.

Enhacements:

  • Consolidated from class-based architecture to functional async/await patterns
  • Simplified from multiple implementation paths to two core functions: runCLI() (synchronous) and runCliAsync() (asynchronous)
  • Removed unused features (timeout management, phase tracking, delegate patterns) that weren't required for munkipkg's use cases
  • Standardized naming to follow Swift conventions (exitCode, stdout, stderr)

Improvements:

  • Replaced blocking usleep() calls with cooperative Task.yield() for better async behavior
  • More efficient resource usage through Swift's structured concurrency
  • Fixed double-negative logic in environment variable handling

errors.swift - Error Type System

Defines an error hierarchy with specific exit codes for different failure scenarios. Implements LocalizedError protocol for proper error message presentation and Swift error handling patterns.

  • Base MunkiPkgError class with custom exit codes
  • Specific error types: ProjectExistsError, InvalidProjectError, ImportFailedError, BuildFailedError
  • Convenience factory methods for creating typed errors
  • Proper errorDescription implementation for user-facing messages

munkipkgoptions.swift - Command-Line Argument Parsing

Leverages ArgumentParser for type-safe CLI option handling with automatic validation and help generation. Groups related options into logical categories for better organization and validation.

  • Structured option groups (Actions, Build options, Create/Import options)
  • Built-in validation preventing invalid option combinations
  • Automatic help text generation
  • Default value handling (e.g., --build as default action)

Unit Test Suite (munkipkgTests/)

Test coverage for core functionality with proper module visibility through @testable import. Includes fixture files for testing configuration formats.

Test coverage:

  • BuildInfo initialization from all formats (plist, json, yaml)
  • Configuration parsing and validation
  • Variable substitution functionality
  • Error handling for malformed configurations
  • Format detection and file reading

Testing and Validation

Build and Development

cd swift/munkipkg && swift build -c release

Build completed successfully with Swift 5.5 in ~2 seconds
Universal binary created at .build/release/munkipkg
Minor non-breaking warnings about Swift 6 compatibility

Unit Tests

swift test

Test run with 12 tests in 2 suites passed after 0.006 seconds
All BuildInfo tests: ✓ PASSED
All munkipkg tests: ✓ PASSED

Test Results:

  • Configuration file parsing (plist, json, yaml)
  • BuildInfo initialization and validation
  • Variable substitution (${version})
  • Error handling for malformed configurations
  • Format detection and file reading
  • Multiple format handling in same directory

Testing

Project Creation:
All three formats (plist, json, yaml) create proper directory structure with correct configuration files.

Package Building:
Successfully builds packages from all project formats with consistent output and proper naming conventions.

Import Functionality:
Successfully imports existing packages with proper payload extraction and metadata preservation.

BOM Export:
Correctly exports Bill-of-Materials information for Git workflow integration.

Compatibility Verification:

  • All existing build-info files work without modification
  • Identical command-line interface and behavior
  • Same package output format and structure
  • Proper error handling and exit codes

How to Test

Build and Install

cd swift/munkipkg
swift build -c release
sudo cp .build/release/munkipkg /usr/local/bin/

Core Functionality Testing

Create projects in all formats

munkipkg --create TestPlist
munkipkg --create --json TestJSON
munkipkg --create --yaml TestYAML

Build packages

munkipkg TestPlist
munkipkg TestJSON
munkipkg TestYAML

Import existing packages

munkipkg --import existing.pkg ImportedProject

Export BOM information

munkipkg --export-bom-info TestPlist

What Changed

Swift Implementation:

swift/munkipkg/
├── Package.swift               # SwiftPM configuration
├── munkipkg/                   # Source files
│   ├── buildinfo.swift         # Configuration handling
│   ├── cliutils.swift          # CLI utilities
│   ├── errors.swift            # Error definitions
│   ├── munkipkg.swift          # Main logic
│   └── munkipkgoptions.swift   # CLI parsing
└── munkipkgTests/              # Test suite

Documentation Updates:

  • Updated README.md for Swift implementation
  • Swift-specific build and deployment instructions
  • Removed Python-specific setup information

Core Features:
- Project creation (plist, json, yaml formats)
- Package building with pkgbuild integration
- Package import (flat and bundle formats)
- BOM export for Git workflow integration

Implementation:
- Swift Package Manager with ArgumentParser and Yams
- macOS 11.0+ target (aligned with Munki v7)
- Async/await for improved performance
- Fixed import functionality Payload directory handling

Components:
- buildinfo.swift: Multi-format configuration handling
- munkipkg.swift: Main CLI implementation
- cliutils.swift: Simplified async CLI utilities
- errors.swift: Error hierarchy with exit codes
- munkipkgoptions.swift: Argument parsing

Testing:
- Core workflows verified (create, build, import, export-bom)
- Format compatibility across all types confirmed
- Unit test suite with module visibility

Documentation:
- Updated README with Swift installation instructions
- Removed Python dependency references
- Added Swift Package Manager build docs

Backward compatibility maintained.
- Updated swift-tools-version from 5.4 to 5.5
- Fixed test resource loading with Bundle.module
- Added explicit resource declaration in Package.swift
- Updated documentation to reflect Swift 5.5 requirement

All unit tests pass (12 tests in 2 suites)
Release build completes successfully in ~2 seconds
Copilot AI review requested due to automatic review settings September 30, 2025 17:57
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Completes the Swift implementation of munkipkg to achieve feature parity with the original Python version, targeting macOS 11+ with Universal binary support. The implementation leverages Swift's modern features including async/await, ArgumentParser, and native YAML support.

  • Adds full command-line interface with project creation, package building, and import functionality
  • Implements comprehensive build configuration handling for plist, JSON, and YAML formats
  • Provides async CLI utilities for external tool execution with proper error handling

Reviewed Changes

Copilot reviewed 10 out of 12 changed files in this pull request and generated no comments.

Show a summary per file
File Description
Package.swift Swift Package Manager configuration with dependencies for ArgumentParser and Yams
munkipkg.swift Main application logic implementing all core functionality (create, build, import, BOM export)
munkipkgoptions.swift Removes YAML validation restriction, enabling full YAML support
buildinfo.swift Adds complete YAML support and public API access for testing
cliutils.swift Streamlines CLI execution with async/await patterns, removing ~290 lines of unused code
errors.swift Adds structured error hierarchy with specific exit codes and factory methods
README.md Updates documentation for Swift implementation with installation and usage instructions
Test files Adds proper module imports and modernizes test resource handling

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@gregneagle
Copy link
Contributor

I appreciate the enthusiasm. This is a huge PR. How much of this was generated via AI?

For my own projects, I write them partially to understand/learn the language, the frameworks, the coding approaches, and the algorithms. Accepting AI-generated code or big PRs that I don't really understand doesn't really help that goal.

Happy to have a discussion here.

@rodchristiansen
Copy link
Contributor Author

Assisted yes! I've been using Claude to learn Swift this whole year and having a back and forth with it to learn and understand the language.

It's been a goal of mine to build apps so I am using the work projects we love to use for Mac admin'ing as a place to learn and experiment. Always better when you have a specific something you want to do and a project as it so much more tangible and direct to learn.

But if it looks as if I am doing a prompt and accepting all changes (or git add .) and walking away that's not the case 😅.

Heavily used for running the tests and generating test units, which helps and not my forté. The commit messages and PR were also assisted for speed, but I read and review because I never like the tone or how authoritative it sounds.

I need to learn to send smaller PR.

- Rewrote performBuild() with workflow:
  * Create build directory structure
  * Build component packages with pkgbuild
  * Support distribution-style packages with productbuild
  * Implement code signing with identity, keychain, and timestamp
  * Implement notarization with keychain-profile authentication
  * Implement stapling functionality
  * Add proper error handling and output control

- Enhanced runCliAsync in cliutils to support all build commands
- Added analyzePermissionsInBom() function to parse BOM file metadata
  * Extracts mode, uid, gid, and size information
  * Returns structured permission map for analysis
- Enhanced notarization to support dual authentication methods:
  * Keychain-profile method (existing)
  * Apple ID authentication with apple_id, team_id, password
  * Optional asc_provider for multi-team accounts
- Added additional certificates support in signing:
  * Uses additionalCertNames from SigningInfo
  * Iterates cert names with --certs flag for productbuild
- Added MissingBomFileError to errors.swift for better error handling
- Integrated permission analysis into syncFromBomInfo()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants