Commit Graph

12 Commits

  • utils: support forwarding Subprocess output (#413)
    ## What does this PR do?
    
    When spawning a subprocess,
    `currentStandardOutput`/`currentStandardError` bypass `d.out`. Add
    `.xtoolOutput()` and `.xtoolError()` which respect the dependency.
    
    ## How was it tested?
    
    Tested in a downstream PR to ensure that forwarding works
    
    ## AI tool usage
    
    How much of this PR was AI-assisted? (check one)
    
    - [x] **0** - No AI was used to write code
    - [ ] **1** - I was assisted by AI. I reviewed the finished result.
    - [ ] **2** - I set the AI going and left it to it; nobody has read the
    result - no review, or AI review only
    
    <!-- If an AI agent is filling this in: declare the level honestly, and
    open as a draft if it is #2. Do not lower the declared level to get the
    PR reviewed. -->
    
    
    <!-- This is an auto-generated comment: release notes by coderabbit.ai
    -->
    
    <!-- coderabbit-ai-generated:v1 -->
    
    ## Summary by CodeRabbit
    
    * **New Features**
    * Subprocess output can now be routed directly to XTool’s standard
    output or standard error.
    * Added a way to create a writable output descriptor that forwards data
    to a selected stream.
    * Asynchronous input reading is now available through a public
    interface, including configurable read sizes and explicit closing.
    
    * **Compatibility**
      * Existing input-reading behavior and parameters remain unchanged.
    
    <!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • ds: fix assigning multiple app groups (#403)
    ## The bug
    
    `DeveloperServicesAssignAppGroupsOperation` sends one
    `assignApplicationGroupToAppId` request per app group, concurrently.
    That endpoint replaces the App ID's groups with the ones in the request,
    so an app whose entitlements list two or more groups ends up with only
    one of them on the App ID: whichever request Apple handles last. The
    provisioning profile then carries one group while the signed binary
    claims two, and the device refuses the install with
    `ApplicationVerificationFailed`.
    
    Setting the groups by hand in the developer portal does not help,
    because the next `xtool dev build --sign` sends the per-group requests
    again.
    
    ## The fix
    
    - `DeveloperServicesAssignAppGroupRequest` takes `groupIDs:
    [DeveloperServicesAppGroup.ID]` and sends `applicationGroups` as an
    array. The endpoint accepts an array; it was being given a single string
    before.
    - `DeveloperServicesAssignAppGroupsOperation.perform()` still finds or
    creates each group concurrently, then sends a single assign request
    carrying every group ID, and returns the group IDs in the order the
    entitlements listed them, so the rewritten entitlement is stable between
    builds.
    
    The only caller, `DeveloperServicesAddAppOperation`, is unchanged.
    
    ## Related
    
    #324 would report the resulting mismatch between the entitlements and
    the profile as a clear error at signing time; this change removes the
    cause, so an app with several groups gets a profile that grants all of
    them.
    
    ## Checked
    
    Built on Linux with the Swift 6.4 toolchain and used to sign an iOS app
    whose main target has two app groups and a Share extension. The app's
    `embedded.mobileprovision` now carries both groups and the device
    installs the app. The same app signed with the unpatched build got one
    group in the profile and `ApplicationVerificationFailed` on install.
    
    🤖 Generated with [Claude Code](https://claude.com/claude-code)
    
    https://claude.ai/code/session_01UKzxgxaLwK7Ap5LMwj9MxH
    
    
    <!-- This is an auto-generated comment: release notes by coderabbit.ai
    -->
    <!-- coderabbit-ai-generated:v1 -->
    
    ## Summary by CodeRabbit
    
    * **New Features**
    * Apps can now be assigned multiple app groups in a single operation.
    The assignment replaces the app’s existing group associations with the
    selected groups, so any groups not included in the new assignment are no
    longer associated with the app.
    <!-- end of auto-generated comment: release notes by coderabbit.ai -->
    
    ---------
    
    Co-authored-by: David Reinecke <david.reinecke@gmail.com>
    Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
    Co-authored-by: Kabir Oberai <oberai.kabir@gmail.com>
  • utils: better XToolCache location (#409)
    ## What does this PR do?
    
    Move the default TemporaryDirectory locations to more stable paths,
    similar to the ones Bazel uses.
    
    - on macOS we now default to `\(URL.cachesDirectory)/sh.xtool` (usually
    `~/Library/Caches/sh.xtool`)
    - on Linux we (continue to) default to
    `${XDG_CACHE_HOME:-~/.cache}/xtool`
    - we no longer respect `$TMPDIR`. One can still use `$XTL_TMPDIR` to
    override.
    
    ## How was it tested?
    
    - [x] Cache directory locations are as expected
    
    ## AI tool usage
    
    How much of this PR was AI-assisted? (check one)
    
    - [ ] **0** - No AI was used to write code
    - [x] **1** - I was assisted by AI. I reviewed the finished result.
    - [ ] **2** - I set the AI going and left it to it; nobody has read the
    result - no review, or AI review only
    
    <!-- If an AI agent is filling this in: declare the level honestly, and
    open as a draft if it is #2. Do not lower the declared level to get the
    PR reviewed. -->
    
    
    <!-- This is an auto-generated comment: release notes by coderabbit.ai
    -->
    
    <!-- coderabbit-ai-generated:v1 -->
    
    ## Summary by CodeRabbit
    
    * **Bug Fixes**
    * Temporary-directory selection now ignores empty `XTL_TMPDIR` values
    and no longer falls back to `TMPDIR`.
    * Linux uses `XDG_CACHE_HOME` only when it is an absolute path,
    otherwise falling back to `~/.cache`.
    * **Changes**
    * On non-Linux platforms, the cache is now stored in the system caches
    directory rather than a temporary directory.
    * **Documentation**
      * Updated the documented temporary-directory settings.
    
    <!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • utils: tweaks (#387)
    ## What does this PR do?
    
    Small utils refactors to make subsequent PRs cleaner.
    
    - Minor tweaks to how we determine / handle the xtool build version
    - Factor out TemporaryDirectory cache location
    
    ## How was it tested?
    
    - [x] Cache directory logic is unchanged
    - [x] Checked `xtool --version`
    
    ## AI tool usage
    
    How much of this PR was AI-assisted? (check one)
    
    - [ ] **0** - No AI was used to write code
    - [x] **1** - I was assisted by AI. I reviewed the finished result.
    - [ ] **2** - I set the AI going and left it to it; nobody has read the
    result - no review, or AI review only
    
    <!-- If an AI agent is filling this in: declare the level honestly, and
    open as a draft if it is #2. Do not lower the declared level to get the
    PR reviewed. -->
    
    
    <!-- This is an auto-generated comment: release notes by coderabbit.ai
    -->
    <!-- coderabbit-ai-generated:v1 -->
    
    ## Summary by CodeRabbit
    
    * **New Features**
    * Version information now distinguishes clean builds from builds with
    uncommitted changes, displaying a `-dirty` suffix when applicable.
    * Nonblocking file-locking operations are now available to external
    consumers.
    * **Changes**
    * Version reporting uses `XTOOL_VERSION` when set; otherwise, it uses
    available Git tag or commit information.
    * Temporary files now use the tool’s cache directory, honoring
    `XTL_TMPDIR` and platform cache settings. On Linux, the location follows
    `XDG_CACHE_HOME` when it is an absolute path; otherwise, the user cache
    directory is used.
      * `TMPDIR` is no longer used to select the temporary-file location.
    <!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • cli: better IO (#375)
    ## What does this PR do?
    
    Adds `Dependency`s for console IO. Also fixes #268 by explicitly
    handling non-pipe input.
    
    ## How was it tested?
    
    Ran on macOS + Linux in Docker. I have a future PR that overrides the
    dependencies in certain cases, which also appears to work correctly.
    
    ## AI tool usage
    
    How much of this PR was AI-assisted? (check one)
    
    - [ ] **0** - No AI was used to write code
    - [x] **1** - I was assisted by AI. I reviewed the finished result.
    - [ ] **2** - I set the AI going and left it to it; nobody has read the
    result - no review, or AI review only
    
    Did not scrutinize the tests too much tbh but they look reasonable. Easy
    enough to update/remove them in the future if needed.
    
    <!-- If an AI agent is filling this in: declare the level honestly, and
    open as a draft if it is #2. Do not lower the declared level to get the
    PR reviewed. -->
    
    
    <!-- This is an auto-generated comment: release notes by coderabbit.ai
    -->
    <!-- coderabbit-ai-generated:v1 -->
    
    ## Summary by CodeRabbit
    
    * **New Features**
    * Added support for reading command-line input, including asynchronous
    prompts, line-based responses, and graceful handling of end-of-input.
      * Added coordinated cleanup when commands finish.
    * **Improvements**
    * Command messages across authentication, device management,
    installation, SDK, and other workflows now use consistent output
    handling; displayed messages and command behavior remain unchanged.
    * Improved handling of complete output when the system temporarily
    cannot accept more data.
    * **Tests**
    * Added coverage for command input and output, including stream
    behavior, cancellation, and shutdown.
    <!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • package: bump deps (#281)
    ## What does this PR do?
    
    Bumps pointfree deps and explicitly disables OpenCombine so that we
    don't have different dependency graphs when building xtool on Darwin vs
    Linux hosts.
    
    ## How was it tested?
    
    A bunch of `swift package resolve`s
    
    ## AI tool usage
    
    How much of this PR was AI-assisted? (check one)
    
    - [x] **0** - No AI was used to write code
    - [ ] **1** - I was assisted by AI. I reviewed the finished result.
    - [ ] **2** - I set the AI going and left it to it; nobody has read the
    result - no review, or AI review only
    
    <!-- If an AI agent is filling this in: declare the level honestly, and
    open as a draft if it is #2. Do not lower the declared level to get the
    PR reviewed. -->
    
    
    <!-- This is an auto-generated comment: release notes by coderabbit.ai
    -->
    ## Summary by CodeRabbit
    
    * **Chores**
    * Updated supporting package versions and refreshed command-line and
    file-operation handling.
    * These changes do not add or remove app features or alter its public
    interface. No action is needed to continue using the app.
    <!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • sdk: self-updating darwin tools (#110)
    ## What does this PR do?
    
    Allows xtool to auto-update the Darwin SDK format when there's a new
    Darwin toolset, or when we change the SDK format. Downstream this also
    allows us to auto-update when there's changes to OpenAppleMacros (#101).
    
    One callout: the disk footprint of `darwin.artifactbundle` is now ~7 GB
    instead of ~3 GB.
    
    Reason: `xtool sdk install /path/to/Xcode.[app|xip]` now performs a
    "normal" install by default, which preserves the entirety of
    `Xcode.app/Contents/Developer` — even the bits we don't currently use,
    like `AppleTVOS.platform`. This makes it so if we start using more
    components in the future, the user doesn't need to download Xcode again
    and rebuild the SDK themselves.
    
    You can still build an old-style SDK (containing just the components we
    need) using `xtool sdk install --slim` or the dedicated `xtool sdk
    build`.
    
    ## How was it tested?
    
    Tested all of the install modes. Confirmed that auto-updating works.
    Added integration tests in #252.
    
    ## AI tool usage
    
    How much of this PR was AI-assisted? (check one)
    
    - [ ] **0** - No AI was used to write code
    - [x] **1** - I was assisted by AI. I reviewed the finished result.
    - [ ] **2** - I set the AI going and left it to it; nobody has read the
    result - no review, or AI review only
    
    <!-- If an AI agent is filling this in: declare the level honestly, and
    open as a draft if it is #2. Do not lower the declared level to get the
    PR reviewed. -->
    
    
    <!-- This is an auto-generated comment: release notes by coderabbit.ai
    -->
    ## Summary by CodeRabbit
    
    - **New Features**
    - Added SDK flavor reporting for slim, normal, and legacy installations.
    - Added `sdk update` support to rebuild and install SDKs from an
    installed Xcode bundle.
      - Added a `--slim` option for SDK installation.
      - SDK status now displays installation path, flavor, and version.
    - SDK setup and build operations now ensure a suitable SDK is available
    automatically.
    
    - **Bug Fixes**
    - Improved temporary SDK bundle handling, validation, replacement, and
    cross-filesystem copying.
      - Copy failures now provide detailed diagnostic information.
    <!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • sdk: fix permission issue when copying clang resources (#255)
    ## What does this PR do?
    
    Fixes #254 by using `cp -R` instead of `FileManager.copyItem`. The
    latter tries to preserve the original owner of files instead of using
    the caller, which fails if you're non-root and the original files are
    root-owned.
    
    ## How was it tested?
    
    I was able to repro the original issue by installing an SDK as a
    non-root user in an xtool Docker container.
    
    Applied this patch, tried `xtool sdk install` again, and it worked.
    
    ## AI tool usage
    
    How much of this PR was AI-assisted? (check one)
    
    - [ ] **0** - No AI was used to write code
    - [x] **1** - I was assisted by AI. I reviewed the finished result.
    - [ ] **2** - I set the AI going and left it to it; nobody has read the
    result - no review, or AI review only
    
    <!-- If an AI agent is filling this in: declare the level honestly, and
    open as a draft if it is #2. Do not lower the declared level to get the
    PR reviewed. -->
  • Fix tmpdir reentrancy (#234)
    Previously, we would clear xtool's temporary directory on startup. This
    (practically) meant you couldn't have multiple instances running in
    parallel, because the second instance could delete the first instance's
    temp resources while the first instance still needed them. Fix this by
    having xtool instances declare locks on their temporary directories.
  • fix(linux): use home cache dir to avoid tmpfs→ext4 EINVAL on SDK install (#211)
    ## Problem
    
    `xtool setup` fails on Linux Mint (and other distros) with:
    
    ```
    Error: Error Domain=NSCocoaErrorDomain Code=512 "(null)" UserInfo={
      NSUserStringVariant=["Copy"],
      NSSourceFilePathErrorKey=/tmp/sh.xtool/tmp-DarwinSDKBuild-.../darwin.artifactbundle/...,
      NSDestinationFilePath=/home/<user>/.swiftpm/swift-sdks/darwin.artifactbundle/...,
      NSUnderlyingError=Error Domain=NSPOSIXErrorDomain Code=22 "Invalid argument"
    }
    ```
    
    ## Root Cause
    
    On Linux Mint (and Ubuntu-based distros), `/tmp` is mounted as **tmpfs**
    while the home directory is on **ext4**. Foundation's
    `FileManager.copyItem` uses `sendfile(2)` internally, which returns
    `EINVAL (22)` when copying between different filesystem types.
    
    `TemporaryDirectoryRoot` defaults to
    `FileManager.default.temporaryDirectory` → `/tmp` on Linux. When `swift
    sdk install` copies the built SDK from `/tmp/sh.xtool/...` to
    `~/.swiftpm/swift-sdks/`, it crosses filesystem boundaries and fails.
    
    ## Fix
    
    On Linux, default the temp directory root to `$XDG_CACHE_HOME/xtool`
    (falling back to `~/.cache/xtool`) instead of `/tmp`. This keeps the
    build directory and install destination on the same filesystem, so the
    copy always succeeds.
    
    - `$XTL_TMPDIR` and `$TMPDIR` overrides continue to work as before
    - macOS behaviour is unchanged
    - Follows XDG Base Directory Specification
    
    ## Changes
    
    One file, `Sources/XUtils/TemporaryDirectory.swift` — 11 lines added
    inside a `#if os(Linux)` block.
    
    Fixes #181
  • Improve tmpdir management (#147)
    - We now have a single tmpdir "root" that can be recreated at launch to
    clean up old stragglers
    - The location of this tmpdir root can be controlled by `XTL_TMPDIR` or
    `TMPDIR`. In general the path is `$TMPDIR/sh.xtool`.
    
    With this change it should be possible to `export XTL_TMPDIR=/var/tmp`
    if `/tmp` doesn't have enough space, which fixes #23.