The Problem
iOS developers on Linux, Windows, or macOS need a way to compile, sign, and install SwiftPM‑based apps without Xcode. Apple’s tooling is macOS‑only, so teams that work on CI runners or non‑macOS workstations cannot automate builds or device deployment.
What This Does
xtool supplies a command‑line replacement for Xcode that works on any platform supporting SwiftPM. The core CLI lives in Sources/xtool/XTool.swift, which defines the @main entry point and dispatches sub‑commands implemented in the Sources/XToolSupport/ hierarchy (e.g., InstallCommand.swift, AuthCommand.swift). The library side is exposed through the XKit module (e.g., Sources/XKit/DeveloperServices/* and Sources/XKit/GrandSlam/*), allowing other Swift packages to call Apple Developer Services directly.
Documentation and example scripts are under Documentation/xtool.docc/, while platform‑specific packaging files are in macOS/ (Ruby Gemfile for the macOS helper) and Linux/ (desktop shortcut, build script).
How It Is Wired
- Entry point –
Sources/xtool/XTool.swiftcontains the@mainstruct that parses the CLI (--help, sub‑command selection). - Command routing – The
XToolstruct creates aCommandRegistry(seeSources/XToolSupport/DSCommands/DSCommand.swift) and maps each sub‑command name to a concrete class such asInstallCommand.swiftorAuthCommand.swift. - Core work –
InstallCommand.swift→Sources/XKit/Installation/IPAInstaller.swift→Sources/XKit/Signer/AutoSigner.swift→ low‑level C helpers inSources/CXKit/(mobileprovision.c,version.c).AuthCommand.swift→Sources/XKit/DeveloperServices/DeveloperServicesLoginManager.swift→ network layer inSources/XKit/HTTPClientProtocol/AsyncHTTPClient+HTTP.swift. *NewCommand.swiftscaffolds a new SwiftPM project using templates inDocumentation/xtool.docc/First-app-code/. - External effects – Network calls go through the Swift
AsyncHTTPClientwrapper; signing writes files to a temporary directory (Sources/XUtils/TemporaryDirectory.swift). No database access is present. - Blast radius – The largest single file is
Sources/DeveloperAPI/Generated/Client.swift(6,648 lines). Because it aggregates all generated OpenAPI client code, any change ripples through every developer‑service operation. The internal module graph shows a single module with zero import edges, so the codebase is flat but heavily concentrated in a few files.
No circular import cycles were detected; the import graph consists of one internal module with no edges.
How To Use It
# Clone and enter the repo
git clone https://github.com/moses-y/xtool
cd xtool
# Build the CLI (Makefile provides a default target)
make # or: swift build -c release
# Or run inside a container
docker build -t xtool .
docker run --rm -v "$HOME/.config/xtool:/root/.config/xtool" xtool --help
Configuration – Apple Developer authentication is required. Run xtool auth login (implemented in Sources/XToolSupport/AuthCommand.swift) and follow the on‑screen prompts; the command stores credentials in the user config directory ($HOME/.config/xtool). No additional secret files are committed to the repo.
Running a build – After authentication, create a project (xtool new MyApp) and build it with xtool dev. The dev sub‑command invokes Sources/XKit/Installation/AppInstaller.swift, which packages the SwiftPM product, signs it via AutoSigner, and pushes the IPA to a connected device.
Real‑World Use
A CI pipeline on Linux can containerize xtool, authenticate via a CI‑safe token, and execute:
- name: Build iOS app
run: |
docker run --rm -v $PWD:/src xtool dev --project MyApp
- name: Deploy to device
run: |
docker run --rm -v $PWD:/src xtool install --ipa MyApp.ipa
This replaces the typical macOS‑only Xcode build step with a reproducible, cross‑platform workflow.
Code Health & Issues
- High – Cognitive load – Deep nesting (max indent depth 8) in files such as
Sources/DeveloperAPI/Generated/Client.swift,Sources/PackLib/Packer.swift,Sources/XKit/DeveloperServices/App IDs/DeveloperServicesAddAppOperation.swift. - High – Clarity – Repeated 6‑line shell blocks across 20 documentation scripts (
build-2.sh,build-3.sh, etc.). - High – Oversized file –
Sources/DeveloperAPI/Generated/Client.swift(6,648 lines). - Medium – Cognitive load – High branching density in
Sources/PackLib/PackSchema.swift,Sources/PackLib/Process+Helpers.swift,Sources/XKit/DeveloperServices/OpenAPI/DeveloperAPIPages.swift. - Low – Clarity – Three stray
TODO/FIXMEmarkers inSources/XToolSupport/SDKBuilder.swift.
No missing license, CI, or Dockerfile; tests exist (Tests/XToolTests/MatcherTests.swift). Secrets are not present in the repository.
The Bottom Line
xtool delivers a functional, cross‑platform Xcode substitute with a clear CLI surface and a reusable Swift library. The codebase is small in module count but concentrates complexity in a few large, deeply nested files, which will increase maintenance effort. Teams that need Linux/Windows iOS build pipelines will find it usable, but expect to invest in refactoring the oversized generated client and reducing nesting to keep future changes manageable.