Full Code of darrarski/xcframework-maker for AI

main f59c1c46f09a cached
42 files
55.4 KB
15.5k tokens
1 requests
Download .txt
Repository: darrarski/xcframework-maker
Branch: main
Commit: f59c1c46f09a
Files: 42
Total size: 55.4 KB

Directory structure:
gitextract_2cuer62l/

├── .gitignore
├── .swiftpm/
│   └── xcode/
│       └── xcshareddata/
│           └── xcschemes/
│               ├── XCFrameworkMaker.xcscheme
│               └── make-xcframework.xcscheme
├── LICENSE
├── Package.resolved
├── Package.swift
├── README.md
├── Sources/
│   ├── XCFrameworkMaker/
│   │   ├── Actions/
│   │   │   ├── AddArm64Simulator.swift
│   │   │   ├── CopyFramework.swift
│   │   │   ├── CopyPath.swift
│   │   │   ├── CreateDir.swift
│   │   │   ├── CreateTempDir.swift
│   │   │   ├── CreateXCFramework.swift
│   │   │   ├── DeletePath.swift
│   │   │   ├── GetArchs.swift
│   │   │   ├── LipoCreate.swift
│   │   │   ├── LipoExtract.swift
│   │   │   ├── LipoThin.swift
│   │   │   ├── Log.swift
│   │   │   ├── MakeXCFramework.swift
│   │   │   └── RunShellCommand.swift
│   │   └── Models/
│   │       ├── Arch.swift
│   │       ├── LogLevel.swift
│   │       └── Path.swift
│   └── make-xcframework/
│       ├── MainCommand.swift
│       └── main.swift
└── Tests/
    └── XCFrameworkMakerTests/
        ├── Actions/
        │   ├── AddArm64SimulatorTests.swift
        │   ├── CopyFrameworkTests.swift
        │   ├── CopyPathTests.swift
        │   ├── CreateDirTests.swift
        │   ├── CreateTempDirTests.swift
        │   ├── CreateXCFrameworkTests.swift
        │   ├── DeletePathTests.swift
        │   ├── GetArchsTests.swift
        │   ├── LipoCreateTests.swift
        │   ├── LipoExtractTests.swift
        │   ├── LipoThinTests.swift
        │   ├── LogTests.swift
        │   ├── MakeXCFrameworkTests.swift
        │   └── RunShellCommandTests.swift
        └── Models/
            ├── LogLevelTests.swift
            └── PathTests.swift

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata


================================================
FILE: .swiftpm/xcode/xcshareddata/xcschemes/XCFrameworkMaker.xcscheme
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
   LastUpgradeVersion = "1250"
   version = "1.3">
   <BuildAction
      parallelizeBuildables = "YES"
      buildImplicitDependencies = "YES">
      <BuildActionEntries>
         <BuildActionEntry
            buildForTesting = "YES"
            buildForRunning = "YES"
            buildForProfiling = "YES"
            buildForArchiving = "YES"
            buildForAnalyzing = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "XCFrameworkMaker"
               BuildableName = "XCFrameworkMaker"
               BlueprintName = "XCFrameworkMaker"
               ReferencedContainer = "container:">
            </BuildableReference>
         </BuildActionEntry>
      </BuildActionEntries>
   </BuildAction>
   <TestAction
      buildConfiguration = "Debug"
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      shouldUseLaunchSchemeArgsEnv = "YES"
      codeCoverageEnabled = "YES">
      <Testables>
         <TestableReference
            skipped = "NO">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "XCFrameworkMakerTests"
               BuildableName = "XCFrameworkMakerTests"
               BlueprintName = "XCFrameworkMakerTests"
               ReferencedContainer = "container:">
            </BuildableReference>
         </TestableReference>
      </Testables>
   </TestAction>
   <LaunchAction
      buildConfiguration = "Debug"
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      launchStyle = "0"
      useCustomWorkingDirectory = "NO"
      ignoresPersistentStateOnLaunch = "NO"
      debugDocumentVersioning = "YES"
      debugServiceExtension = "internal"
      allowLocationSimulation = "YES">
   </LaunchAction>
   <ProfileAction
      buildConfiguration = "Release"
      shouldUseLaunchSchemeArgsEnv = "YES"
      savedToolIdentifier = ""
      useCustomWorkingDirectory = "NO"
      debugDocumentVersioning = "YES">
      <MacroExpansion>
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "XCFrameworkMaker"
            BuildableName = "XCFrameworkMaker"
            BlueprintName = "XCFrameworkMaker"
            ReferencedContainer = "container:">
         </BuildableReference>
      </MacroExpansion>
   </ProfileAction>
   <AnalyzeAction
      buildConfiguration = "Debug">
   </AnalyzeAction>
   <ArchiveAction
      buildConfiguration = "Release"
      revealArchiveInOrganizer = "YES">
   </ArchiveAction>
</Scheme>


================================================
FILE: .swiftpm/xcode/xcshareddata/xcschemes/make-xcframework.xcscheme
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
   LastUpgradeVersion = "1250"
   version = "1.3">
   <BuildAction
      parallelizeBuildables = "YES"
      buildImplicitDependencies = "YES">
      <BuildActionEntries>
         <BuildActionEntry
            buildForTesting = "YES"
            buildForRunning = "YES"
            buildForProfiling = "YES"
            buildForArchiving = "YES"
            buildForAnalyzing = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "make-xcframework"
               BuildableName = "make-xcframework"
               BlueprintName = "make-xcframework"
               ReferencedContainer = "container:">
            </BuildableReference>
         </BuildActionEntry>
      </BuildActionEntries>
   </BuildAction>
   <TestAction
      buildConfiguration = "Debug"
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      shouldUseLaunchSchemeArgsEnv = "YES">
      <Testables>
         <TestableReference
            skipped = "NO">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "XCFrameworkMakerTests"
               BuildableName = "XCFrameworkMakerTests"
               BlueprintName = "XCFrameworkMakerTests"
               ReferencedContainer = "container:">
            </BuildableReference>
         </TestableReference>
      </Testables>
   </TestAction>
   <LaunchAction
      buildConfiguration = "Debug"
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      launchStyle = "0"
      useCustomWorkingDirectory = "NO"
      ignoresPersistentStateOnLaunch = "NO"
      debugDocumentVersioning = "YES"
      debugServiceExtension = "internal"
      allowLocationSimulation = "YES">
      <BuildableProductRunnable
         runnableDebuggingMode = "0">
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "make-xcframework"
            BuildableName = "make-xcframework"
            BlueprintName = "make-xcframework"
            ReferencedContainer = "container:">
         </BuildableReference>
      </BuildableProductRunnable>
   </LaunchAction>
   <ProfileAction
      buildConfiguration = "Release"
      shouldUseLaunchSchemeArgsEnv = "YES"
      savedToolIdentifier = ""
      useCustomWorkingDirectory = "NO"
      debugDocumentVersioning = "YES">
      <BuildableProductRunnable
         runnableDebuggingMode = "0">
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "make-xcframework"
            BuildableName = "make-xcframework"
            BlueprintName = "make-xcframework"
            ReferencedContainer = "container:">
         </BuildableReference>
      </BuildableProductRunnable>
   </ProfileAction>
   <AnalyzeAction
      buildConfiguration = "Debug">
   </AnalyzeAction>
   <ArchiveAction
      buildConfiguration = "Release"
      revealArchiveInOrganizer = "YES">
   </ArchiveAction>
</Scheme>


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2021 Dariusz Rybicki Darrarski

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: Package.resolved
================================================
{
  "object": {
    "pins": [
      {
        "package": "arm64-to-sim",
        "repositoryURL": "https://github.com/darrarski/arm64-to-sim.git",
        "state": {
          "branch": null,
          "revision": "37962d62d7f8d34875f793de510950112d860083",
          "version": "1.0.0"
        }
      },
      {
        "package": "ShellOut",
        "repositoryURL": "https://github.com/JohnSundell/ShellOut.git",
        "state": {
          "branch": null,
          "revision": "e1577acf2b6e90086d01a6d5e2b8efdaae033568",
          "version": "2.3.0"
        }
      },
      {
        "package": "swift-argument-parser",
        "repositoryURL": "https://github.com/apple/swift-argument-parser.git",
        "state": {
          "branch": null,
          "revision": "986d191f94cec88f6350056da59c2e59e83d1229",
          "version": "0.4.3"
        }
      }
    ]
  },
  "version": 1
}


================================================
FILE: Package.swift
================================================
// swift-tools-version:5.4
import PackageDescription

let package = Package(
  name: "xcframework-maker",
  platforms: [
    .macOS(.v11),
  ],
  products: [
    .library(
      name: "XCFrameworkMaker",
      targets: [
        "XCFrameworkMaker",
      ]
    ),
    .executable(
      name: "make-xcframework",
      targets: [
        "make-xcframework",
      ]
    ),
  ],
  dependencies: [
    .package(
      name: "swift-argument-parser",
      url: "https://github.com/apple/swift-argument-parser.git",
      .upToNextMajor(from: "0.4.3")
    ),
    .package(
      name: "ShellOut",
      url: "https://github.com/JohnSundell/ShellOut.git",
      .upToNextMajor(from: "2.3.0")
    ),
    .package(
      name: "arm64-to-sim",
      url: "https://github.com/darrarski/arm64-to-sim.git",
      .upToNextMajor(from: "1.0.0")
    ),
  ],
  targets: [
    .target(
      name: "XCFrameworkMaker",
      dependencies: [
        .product(
          name: "ShellOut",
          package: "ShellOut"
        ),
        .product(
          name: "Arm64ToSim",
          package: "arm64-to-sim"
        ),
      ]
    ),
    .testTarget(
      name: "XCFrameworkMakerTests",
      dependencies: [
        .target(name: "XCFrameworkMaker"),
      ]
    ),
    .executableTarget(
      name: "make-xcframework",
      dependencies: [
        .target(name: "XCFrameworkMaker"),
        .product(
          name: "ArgumentParser",
          package: "swift-argument-parser"
        ),
      ]
    ),
  ]
)


================================================
FILE: README.md
================================================
# xcframework-maker

![swift 5.4](https://img.shields.io/badge/swift-5.4-orange.svg)
![platform macOS](https://img.shields.io/badge/platform-macOS-blue)
![SPM supported](https://img.shields.io/badge/SPM-supported-green)

macOS utility for converting fat-frameworks to SPM-compatible XCFramework with arm64-simulator support.

## 📝 Description

`make-xcframework` is a simple command-line utility written in Swift that creates **XCFramework** file from fat framework files. The resulting XCFramework file can be added as a dependency to your **Swift Package**, using `.binaryTarget` (read more in [official documentation](https://docs.swift.org/package-manager/PackageDescription/PackageDescription.html)).

Optionally, **arm64-simulator** support can be included in the resulting XCFramework to allow development on a computer with **Apple Silicon (M1)** processor without a need to run Xcode through Rosetta.

The `xcframework-maker` Swift Package contains `make-xcframework` that can be used from the command line and `XCFrameworkMaker` library that you can integrate with your Swift Package and use programmatically.

**Note:** [arm64-to-sim](http://github.com/darrarski/arm64-to-sim) is used to "hack" the native (device) **arm64** architecture slice so it can be used in a simulator running on Apple Silicon. This is an experimental feature, and **it can fail for many reasons**. It was tested and proved to be working with the `GoogleInteractiveMediaAds` dynamic fat framework, but your experience may vary.

## 🛠 Build

Use Swift 5.4 for building the utility on macOS:

```sh
swift build -c release
```

You can copy the executable or run it directly from the build directory:

```sh
.build/release/make-xcframework
```

## ▶️ Usage

```
OVERVIEW: Utility for creating XCFramework from legacy fat-framework files.

Use this tool to create XCFramework from legacy fat-framework files. Resulting XCFramework can be
added as a dependency to your Swift Package. Optionally arm64-simulator support can be included in
the resulting XCFramework, so it can be used on M1 Mac without the need to run Xcode through
Rosetta.

USAGE: make-xcframework [-ios <path>] [-tvos <path>] [-arm64sim] -output <path> [-verbose]

OPTIONS:
  -ios <path>             iOS input framework path.
        Provide a path to the iOS fat framework that should be included in the resulting
        XCFramework. Eg "path/to/iOS/Framework.framework"
  -tvos <path>            tvOS input framework path.
        Provide a path to the tvOS fat framework that should be included in the resulting
        XCFramework. Eg "path/to/tvOS/Framework.framework"
  -arm64sim               Add support for arm64 simulator.
        Use device-arm64 architecture slice as a simulator-arm64 architecture slice and include it
        the resulting XCFramework. This makes development possible on M1 Mac without using Rosetta.
  -output <path>          Output directory path.
        Provide a path to a directory where the resulting XCFramework should be created. Eg
        "path/to/output/directory"
  -verbose                Log detailed info to standard output.
        When this flag is provided, detailed information about each performed action is logged to
        standard output.
  -help, -h               Show help information.
```

### Example - GoogleInteractiveMediaAds

1. Download GoogleInteractiveMediaAds fat-frameworks from Google website:
    - [IMA SDK for iOS](https://developers.google.com/interactive-media-ads/docs/sdks/ios/dai/download)
    - [IMA SDK for tvOS](https://developers.google.com/interactive-media-ads/docs/sdks/tvos/dai/download)
2. Unzip downloaded files.
3. Run `make-xcframework`:

    ```sh
    make-xcframework \
      -ios path/to/ios/GoogleInteractiveMediaAds.framework \
      -tvos path/to/tvos/GoogleInteractiveMediaAds.framework \
      -arm64sim \
      -output output/path
    ```

4. Resulting XCFramework will be created in the provided output directory:

    ```sh
    output/path/GoogleInteractiveMediaAds.xcframework
    ```

## ☕️ Do you like the project?

<a href="https://www.buymeacoffee.com/darrarski" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="60" width="217" style="height: 60px !important;width: 217px !important;" ></a>

## 📄 License

Copyright © 2021 Dariusz Rybicki Darrarski

License: [MIT](LICENSE)


================================================
FILE: Sources/XCFrameworkMaker/Actions/AddArm64Simulator.swift
================================================
import Arm64ToSim

/// Adds arm64 simulator support to a framework
public struct AddArm64Simulator {
  var run: (Path, Path, Log?) throws -> Void

  /// Add arm64 simulator support to a framework
  /// - Parameters:
  ///   - deviceFramework: Path to device framework file
  ///   - simulatorFramework: Path to simulator framework file
  ///   - log: Log action (defaults to nil for no logging)
  /// - Throws: Error
  public func callAsFunction(deviceFramework: Path, simulatorFramework: Path, _ log: Log? = nil) throws {
    try run(deviceFramework, simulatorFramework, log)
  }
}

public extension AddArm64Simulator {
  static func live(
    lipoThin: LipoThin = .live(),
    lipoCrate: LipoCreate = .live(),
    arm64ToSim: @escaping (String) throws -> Void = arm64ToSim(_:),
    deletePath: DeletePath = .live()
  ) -> Self {
    .init { deviceFramework, simulatorFramework, log in
      log?(.normal, "[AddArm64Simulator]")
      log?(.verbose, "- deviceFramework: \(deviceFramework.string)")
      log?(.verbose, "- simulatorFramework: \(simulatorFramework.string)")
      let deviceBinary = deviceFramework.addingComponent(deviceFramework.filenameExcludingExtension)
      let simulatorBinary = simulatorFramework.addingComponent(simulatorFramework.filenameExcludingExtension)
      let arm64Binary = Path("\(simulatorBinary.string)-arm64")
      try lipoThin(input: deviceBinary, arch: .arm64, output: arm64Binary, log?.indented())
      try arm64ToSim(arm64Binary.string)
      try lipoCrate(inputs: [simulatorBinary, arm64Binary], output: simulatorBinary, log?.indented())
      try deletePath(arm64Binary, log?.indented())
    }
  }
}


================================================
FILE: Sources/XCFrameworkMaker/Actions/CopyFramework.swift
================================================
/// Creates copy of a framework with provided architectures
public struct CopyFramework {
  var run: (Path, [Arch], Path, Log?) throws -> Path

  /// Create copy of a framework with provided architectures
  /// - Parameters:
  ///   - input: Path to the framework
  ///   - archs: Architectures to be included in the copied framework
  ///   - path: Path to a directory where framework copy will be created
  ///   - log: Log action (defaults to nil for no logging)
  /// - Throws: Error
  /// - Returns: Path to the copied framework
  public func callAsFunction(_ input: Path, archs: [Arch], path: Path, _ log: Log? = nil) throws -> Path {
    try run(input, archs, path, log)
  }
}

public extension CopyFramework {
  static func live(
    createDir: CreateDir = .live(),
    copyPath: CopyPath = .live(),
    deletePath: DeletePath = .live(),
    lipoExtract: LipoExtract = .live()
  ) -> Self {
    .init { input, archs, path, log in
      log?(.normal, "[CopyFramework]")
      log?(.verbose, "- input: \(input.string)")
      log?(.verbose, "- archs: \(archs.map(\.rawValue).joined(separator: ", "))")
      log?(.verbose, "- path: \(path.string)")
      try createDir(path, log?.indented())
      let output = path.addingComponent(input.lastComponent)
      try copyPath(of: input, at: output, log?.indented())
      let outputBinary = output.addingComponent(output.filenameExcludingExtension)
      try deletePath(outputBinary, log?.indented())
      let inputBinary = input.addingComponent(input.filenameExcludingExtension)
      try lipoExtract.callAsFunction(input: inputBinary, archs: archs, output: outputBinary, log?.indented())
      log?(.verbose, "- output: \(output.string)")
      return output
    }
  }
}


================================================
FILE: Sources/XCFrameworkMaker/Actions/CopyPath.swift
================================================
/// Creates copy of file or directory
public struct CopyPath {
  var run: (Path, Path, Log?) throws -> Void

  /// Create copy of file or directory
  /// - Parameters:
  ///   - source: Source file or directory path
  ///   - destination: Destination path
  ///   - log: Log action (defaults to nil for no logging)
  /// - Throws: Error
  public func callAsFunction(of source: Path, at destination: Path, _ log: Log? = nil) throws {
    try run(source, destination, log)
  }
}

public extension CopyPath {
  static func live(
    runShellCommand: RunShellCommand = .live()
  ) -> Self {
    .init { source, destination, log in
      log?(.normal, "[CopyPath]")
      log?(.verbose, "- source: \(source.string)")
      log?(.verbose, "- destination: \(destination.string)")
      _ = try runShellCommand("cp -fR \(source.string) \(destination.string)", log?.indented())
    }
  }
}


================================================
FILE: Sources/XCFrameworkMaker/Actions/CreateDir.swift
================================================
/// Creates directory
public struct CreateDir {
  var run: (Path, Log?) throws -> Void

  /// Create directory at provied path
  /// - Parameters:
  ///   - path: Path of the directory to create
  ///   - log: Log action (defaults to nil for no logging)
  /// - Throws: Error
  public func callAsFunction(_ path: Path, _ log: Log? = nil) throws {
    try run(path, log)
  }
}

public extension CreateDir {
  static func live(
    runShellCommand: RunShellCommand = .live()
  ) -> Self {
    .init { path, log in
      log?(.normal, "[CreateDir]")
      log?(.verbose, "- path: \(path.string)")
      _ = try runShellCommand("mkdir -p \(path.string)", log?.indented())
    }
  }
}


================================================
FILE: Sources/XCFrameworkMaker/Actions/CreateTempDir.swift
================================================
import Foundation

/// Creates new temporary directory
public struct CreateTempDir {
  var run: (Log?) throws -> Path

  /// Create new temporary directory and return its path
  /// - Parameter log: Log action (defaults to nil for no logging)
  /// - Throws: Error
  /// - Returns: Path to new temporary directory
  public func callAsFunction(_ log: Log? = nil) throws -> Path {
    try run(log)
  }
}

public extension CreateTempDir {
  static func live(
    basePath: String = FileManager.default.temporaryDirectory.path,
    randomString: @escaping () -> String = { UUID().uuidString },
    createDir: CreateDir = .live()
  ) -> Self {
    .init { log in
      log?(.normal, "[CreateTempDir]")
      let path = Path(basePath).addingComponent("XCFrameworkMaker_\(randomString())")
      try createDir(path, log?.indented())
      log?(.verbose, "- path: \(path.string)")
      return path
    }
  }
}


================================================
FILE: Sources/XCFrameworkMaker/Actions/CreateXCFramework.swift
================================================
/// Creates XCFramework from provided thin frameworks
public struct CreateXCFramework {
  var run: ([Path], Path, Log?) throws -> Void

  /// Create XCFramework from provided thin frameworks
  /// - Parameters:
  ///   - frameworks: Paths to thin frameworks
  ///   - path: Path to a directory where resulting XCFramework will be created
  ///   - log: Log action (defaults to nil for no logging)
  /// - Throws: Error
  public func callAsFunction(from frameworks: [Path], at path: Path, _ log: Log? = nil) throws {
    try run(frameworks, path, log)
  }
}

public extension CreateXCFramework {
  static func live(
    deletePath: DeletePath = .live(),
    runShellCommand: RunShellCommand = .live()
  ) -> Self {
    .init { frameworks, path, log in
      log?(.normal, "[CreateXCFramework]")
      log?(.verbose, "- frameworks: \n\t\(frameworks.map(\.string).joined(separator: "\n\t"))")
      log?(.verbose, "- path: \(path.string)")
      let frameworkOptions = frameworks.map { "-framework \($0.string)" }.joined(separator: " ")
      let frameworkName = frameworks.first?.filenameExcludingExtension ?? ""
      let output = path.addingComponent("\(frameworkName).xcframework")
      try deletePath(output, log?.indented())
      _ = try runShellCommand(
        "xcodebuild -create-xcframework \(frameworkOptions) -output \(output.string)",
        log?.indented()
      )
    }
  }
}


================================================
FILE: Sources/XCFrameworkMaker/Actions/DeletePath.swift
================================================
/// Deletes file or directory
public struct DeletePath {
  var run: (Path, Log?) throws -> Void

  /// Delete file or directory
  /// - Parameters:
  ///   - path: Path to file or directory to be removed
  ///   - log: Log action (defaults to nil for no logging)
  /// - Throws: Error
  public func callAsFunction(_ path: Path, _ log: Log? = nil) throws {
    try run(path, log)
  }
}

public extension DeletePath {
  static func live(
    runShellCommand: RunShellCommand = .live()
  ) -> Self {
    .init { path, log in
      log?(.normal, "[DeletePath]")
      log?(.verbose, "- path: \(path.string)")
      _ = try runShellCommand("rm -Rf \(path.string)", log?.indented())
    }
  }
}


================================================
FILE: Sources/XCFrameworkMaker/Actions/GetArchs.swift
================================================
/// Gets architectures contained in a framework
public struct GetArchs {
  var run: (Path, Log?) throws -> [Arch]

  /// Get architectures contained in framework
  /// - Parameters:
  ///   - frameworkPath: Path to framework
  ///   - log: Log action (defaults to nil for no logging)
  /// - Throws: Error
  /// - Returns: Architectures contained in the framework
  public func callAsFunction(inFramework frameworkPath: Path, _ log: Log? = nil) throws -> [Arch] {
    try run(frameworkPath, log)
  }
}

public extension GetArchs {
  static func live(
    runShellCommand: RunShellCommand = .live()
  ) -> Self {
    .init { frameworkPath, log in
      log?(.normal, "[GetArchs]")
      log?(.verbose, "- frameworkPath: \(frameworkPath.string)")
      let frameworkName = frameworkPath.filenameExcludingExtension
      let binaryPath = frameworkPath.addingComponent(frameworkName)
      let archs = try runShellCommand("lipo \(binaryPath.string) -archs", log?.indented())
        .components(separatedBy: " ")
        .compactMap(Arch.init(rawValue:))
      log?(.verbose, "- archs: \(archs.map(\.rawValue).joined(separator: ", "))")
      return archs
    }
  }
}


================================================
FILE: Sources/XCFrameworkMaker/Actions/LipoCreate.swift
================================================
/// Use lipo to create binary file from other binary files
public struct LipoCreate {
  var run: ([Path], Path, Log?) throws -> Void

  /// Create binary file from other binary files
  /// - Parameters:
  ///   - inputs: Paths to input files
  ///   - output: Path to output file
  ///   - log: Log action (defaults to nil for no logging)
  /// - Throws: Error
  public func callAsFunction(inputs: [Path], output: Path, _ log: Log? = nil) throws {
    try run(inputs, output, log)
  }
}

public extension LipoCreate {
  static func live(
    runShellCommand: RunShellCommand = .live()
  ) -> Self {
    .init { inputs, output, log in
      log?(.normal, "[LipoCreate]")
      log?(.verbose, "- inputs: \n\t\(inputs.map(\.string).joined(separator: "\n\t"))")
      log?(.verbose, "- output: \(output.string)")
      let input = inputs.map(\.string).joined(separator: " ")
      _ = try runShellCommand("lipo \(input) -create -output \(output.string)", log?.indented())
    }
  }
}


================================================
FILE: Sources/XCFrameworkMaker/Actions/LipoExtract.swift
================================================
/// Use lipo to extract provided architectures from binary file
public struct LipoExtract {
  var run: (Path, [Arch], Path, Log?) throws -> Void

  /// Extract provided architectures from binary file
  /// - Parameters:
  ///   - input: Path to the binary file
  ///   - archs: Architectures to be extracted
  ///   - output: Path to the extracted binary file
  ///   - log: Log action (defaults to nil for no logging)
  /// - Throws: Error
  public func callAsFunction(input: Path, archs: [Arch], output: Path, _ log: Log? = nil) throws {
    try run(input, archs, output, log)
  }
}

public extension LipoExtract {
  static func live(
    runShellCommand: RunShellCommand = .live()
  ) -> Self {
    .init { input, archs, output, log in
      log?(.normal, "[LipoExtract]")
      log?(.verbose, "- input: \(input.string)")
      log?(.verbose, "- archs: \(archs.map(\.rawValue).joined(separator: ", "))")
      log?(.verbose, "- output: \(input.string)")
      let extract = archs.map { "-extract \($0)" }.joined(separator: " ")
      _ = try runShellCommand("lipo \(input.string) \(extract) -output \(output.string)", log?.indented())
    }
  }
}


================================================
FILE: Sources/XCFrameworkMaker/Actions/LipoThin.swift
================================================
/// Use lipo to create thin binary file with provided architecture
public struct LipoThin {
  var run: (Path, Arch, Path, Log?) throws -> Void

  /// Create thin binary file with provided architecture
  /// - Parameters:
  ///   - input: Path to the input file
  ///   - arch: Architecture to be included in the output
  ///   - output: Path to the output file
  ///   - log: Log action (defaults to nil for no logging)
  /// - Throws: Error
  public func callAsFunction(input: Path, arch: Arch, output: Path, _ log: Log? = nil) throws {
    try run(input, arch, output, log)
  }
}

public extension LipoThin {
  static func live(
    runShellCommand: RunShellCommand = .live()
  ) -> Self {
    .init { input, arch, output, log in
      log?(.normal, "[LipoThin]")
      log?(.verbose, "- input: \(input.string)")
      log?(.verbose, "- arch: \(arch.rawValue)")
      log?(.verbose, "- output: \(output.string)")
      _ = try runShellCommand(
        "lipo \(input.string) -thin \(arch.rawValue) -output \(output.string)",
        log?.indented()
      )
    }
  }
}


================================================
FILE: Sources/XCFrameworkMaker/Actions/Log.swift
================================================
/// Logs messages
public struct Log {
  var run: (LogLevel, String) -> Void

  /// Log message
  /// - Parameters:
  ///   - level: Log level
  ///   - message: Message to be logged
  public func callAsFunction(_ level: LogLevel, _ message: String) {
    run(level, message)
  }
}

public extension Log {
  static func live(
    level logginLevel: LogLevel = .normal,
    print: @escaping (String) -> Void = { print($0) }
  ) -> Self {
    .init { level, message in
      guard level <= logginLevel else { return }
      print(message)
    }
  }
}

public extension Log {
  /// Returns modified Log that indents messages with a tab character
  /// - Returns: Log
  func indented() -> Self {
    .init { level, message in
      let indentation = "\t"
      let indentedMessage = message
        .split(separator: "\n")
        .map { indentation + $0 }
        .joined(separator: "\n")
      self.callAsFunction(level, indentedMessage)
    }
  }
}


================================================
FILE: Sources/XCFrameworkMaker/Actions/MakeXCFramework.swift
================================================
import Foundation

/// Creates XCFramework from provided fat frameworks
public struct MakeXCFramework {
  var run: (Path?, Path?, Bool, Path, Log?) throws -> Void

  /// Create XCFramework from provided fat frameworks
  /// - Parameters:
  ///   - iOSPath: Path to iOS fat framework
  ///   - tvOSPath: Path to tvOS fat framework
  ///   - arm64sim: If true, add arm64-simulator support
  ///   - path: Path to a directory where resulting XCFramework will be created
  ///   - log: Log action (defaults to nil for no logging)
  /// - Throws: Error
  public func callAsFunction(
    iOS iOSPath: Path?,
    tvOS tvOSPath: Path?,
    arm64sim: Bool,
    at path: Path,
    _ log: Log? = nil
  ) throws {
    try run(iOSPath, tvOSPath, arm64sim, path, log)
  }
}

extension MakeXCFramework {
  public struct EmptyInputError: LocalizedError, Equatable {
    public init() {}

    public var errorDescription: String? {
      "Empty inputs. Provide at least one input fat framework."
    }
  }
}

public extension MakeXCFramework {
  static func live(
    createTempDir: CreateTempDir = .live(),
    getArchs: GetArchs = .live(),
    copyFramework: CopyFramework = .live(),
    addArm64Simulator: AddArm64Simulator = .live(),
    createXCFramework: CreateXCFramework = .live()
  ) -> Self {
    .init { iOSPath, tvOSPath, arm64sim, output, log in
      log?(.normal, "[MakeXCFramework]")
      log?(.verbose, "- iOSPath: \(iOSPath?.string ?? "nil")")
      log?(.verbose, "- tvOSPath: \(tvOSPath?.string ?? "nil")")
      log?(.verbose, "- arm64sim: \(arm64sim)")
      log?(.verbose, "- output: \(output.string)")

      guard iOSPath != nil || tvOSPath != nil else {
        throw EmptyInputError()
      }

      let tempDir = try createTempDir(log?.indented())
      var thinFrameworks = [Path]()

      if let path = iOSPath {
        let archs = try getArchs(inFramework: path, log?.indented())
        let deviceArchs = [Arch.armv7, .arm64].filter(archs.contains(_:))
        let simulatorArchs = [Arch.i386, .x86_64].filter(archs.contains(_:))
        let deviceOutput = tempDir.addingComponent("ios-device")
        let simulatorOutput = tempDir.addingComponent("ios-simulator")
        let deviceFramework = try copyFramework(path, archs: deviceArchs, path: deviceOutput, log?.indented())
        let simulatorFramework = try copyFramework(path, archs: simulatorArchs, path: simulatorOutput, log?.indented())
        if arm64sim {
          try addArm64Simulator(
            deviceFramework: deviceFramework, simulatorFramework: simulatorFramework,
            log?.indented()
          )
        }
        thinFrameworks.append(contentsOf: [deviceFramework, simulatorFramework])
      }

      if let path = tvOSPath {
        let archs = try getArchs(inFramework: path, log?.indented())
        let deviceArchs = [Arch.armv7, .arm64].filter(archs.contains(_:))
        let simulatorArchs = [Arch.i386, .x86_64].filter(archs.contains(_:))
        let deviceOutput = tempDir.addingComponent("tvos-device")
        let simulatorOutput = tempDir.addingComponent("tvos-simulator")
        let deviceFramework = try copyFramework(path, archs: deviceArchs, path: deviceOutput, log?.indented())
        let simulatorFramework = try copyFramework(path, archs: simulatorArchs, path: simulatorOutput, log?.indented())
        if arm64sim {
          try addArm64Simulator(
            deviceFramework: deviceFramework, simulatorFramework: simulatorFramework,
            log?.indented()
          )
        }
        thinFrameworks.append(contentsOf: [deviceFramework, simulatorFramework])
      }

      try createXCFramework(from: thinFrameworks, at: output, log?.indented())
    }
  }
}


================================================
FILE: Sources/XCFrameworkMaker/Actions/RunShellCommand.swift
================================================
import ShellOut

/// Execute shell command
public struct RunShellCommand {
  var run: (String, Log?) throws -> String

  /// Execure shell command
  /// - Parameters:
  ///   - command: Command to execute
  ///   - log: Log action (defaults to nil for no logging)
  /// - Throws: Error
  /// - Returns: Shell command output
  public func callAsFunction(_ command: String, _ log: Log? = nil) throws -> String {
    try run(command, log)
  }
}

public extension RunShellCommand {
  static func live(
    shellOut: @escaping (String) throws -> String = { try shellOut(to: $0) }
  ) -> Self {
    .init { command, log in
      log?(.normal, "[RunShellCommand]")
      log?(.verbose, "- command: \(command)")
      let output = try shellOut(command)
      log?(.verbose, "- output: \(output)")
      return output
    }
  }
}


================================================
FILE: Sources/XCFrameworkMaker/Models/Arch.swift
================================================
public enum Arch: String {
  case i386
  case x86_64
  case armv7
  case arm64
}


================================================
FILE: Sources/XCFrameworkMaker/Models/LogLevel.swift
================================================
public enum LogLevel: Equatable, CaseIterable {
  case normal
  case verbose
}

extension LogLevel: Comparable {
  public static func < (lhs: LogLevel, rhs: LogLevel) -> Bool {
    allCases.firstIndex(of: lhs)! < allCases.firstIndex(of: rhs)!
  }
}


================================================
FILE: Sources/XCFrameworkMaker/Models/Path.swift
================================================
import Foundation

public struct Path: Equatable, Hashable {
  public init(_ string: String) {
    self.string = string
  }

  var string: String
}

extension Path {
  var lastComponent: String {
    string.split(separator: "/").last.map(String.init) ?? ""
  }

  var fileExtension: String? {
    let lastComponent = self.lastComponent
    guard lastComponent.contains(".") else { return nil }
    return lastComponent.split(separator: ".").last.map(String.init)
  }

  var filenameExcludingExtension: String {
    let lastComponent = self.lastComponent
    guard lastComponent.contains(".") else { return lastComponent }
    var filenameComponents = lastComponent.split(separator: ".").map(String.init)
    guard filenameComponents.count > 1 else { return lastComponent }
    filenameComponents.removeLast()
    return filenameComponents.joined(separator: ".")
  }

  func addingComponent(_ component: String) -> Path {
    var newString = string
    if newString.hasSuffix("/") == false {
      newString.append("/")
    }
    newString.append(component)
    return Path(newString)
  }
}


================================================
FILE: Sources/make-xcframework/MainCommand.swift
================================================
import ArgumentParser
import Foundation
import XCFrameworkMaker

struct MainCommand: ParsableCommand {
  static var makeXCFramework: MakeXCFramework = .live()

  // MARK: - ParsableCommand

  static let configuration = CommandConfiguration(
    commandName: "make-xcframework",
    abstract: "Utility for creating XCFramework from legacy fat-framework files.",
    discussion: "Use this tool to create XCFramework from legacy fat-framework files. Resulting XCFramework can be added as a dependency to your Swift Package. Optionally arm64-simulator support can be included in the resulting XCFramework, so it can be used on M1 Mac without the need to run Xcode through Rosetta.",
    helpNames: [.short, .customLong("help", withSingleDash: true)]
  )

  struct InputOptions: ParsableArguments {
    @Option(
      name: .customLong("ios", withSingleDash: true),
      help: ArgumentHelp(
        "iOS input framework path.",
        discussion: "Provide a path to the iOS fat framework that should be included in the resulting XCFramework. Eg \"path/to/iOS/Framework.framework\"",
        valueName: "path"
      ),
      completion: .file(extensions: ["framework"])
    )
    var ios: String?

    @Option(
      name: .customLong("tvos", withSingleDash: true),
      help: ArgumentHelp(
        "tvOS input framework path.",
        discussion: "Provide a path to the tvOS fat framework that should be included in the resulting XCFramework. Eg \"path/to/tvOS/Framework.framework\"",
        valueName: "path"
      ),
      completion: .file(extensions: ["framework"])
    )
    var tvos: String?

    func validate() throws {
      guard ios != nil || tvos != nil else {
        throw MakeXCFramework.EmptyInputError()
      }
    }
  }

  @OptionGroup
  var inputs: InputOptions

  @Flag(
    name: .customLong("arm64sim", withSingleDash: true),
    help: ArgumentHelp(
      "Add support for arm64 simulator.",
      discussion: "Use device-arm64 architecture slice as a simulator-arm64 architecture slice and include it the resulting XCFramework. This makes development possible on M1 Mac without using Rosetta."
    )
  )
  var arm64sim: Bool = false

  @Option(
    name: .customLong("output", withSingleDash: true),
    help: ArgumentHelp(
      "Output directory path.",
      discussion: "Provide a path to a directory where the resulting XCFramework should be created. Eg \"path/to/output/directory\"",
      valueName: "path"
    ),
    completion: .directory
  )
  var output: String

  @Flag(
    name: .customLong("verbose", withSingleDash: true),
    help: ArgumentHelp(
      "Log detailed info to standard output.",
      discussion: "When this flag is provided, detailed information about each performed action is logged to standard output."
    )
  )
  var verbose: Bool = false

  func run() throws {
    try Self.makeXCFramework(
      iOS: inputs.ios.map(Path.init(_:)),
      tvOS: inputs.tvos.map(Path.init(_:)),
      arm64sim: arm64sim,
      at: Path(output),
      verbose ? Log.live(level: .verbose) : nil
    )
  }
}


================================================
FILE: Sources/make-xcframework/main.swift
================================================
MainCommand.main()


================================================
FILE: Tests/XCFrameworkMakerTests/Actions/AddArm64SimulatorTests.swift
================================================
import XCTest
@testable import XCFrameworkMaker

final class AddArm64SimulatorTests: XCTestCase {
  enum Action: Equatable {
    case didLipoThin(Path, Arch, Path)
    case didLipoCreate([Path], Path)
    case didArm64ToSim(String)
    case didDeletePath(Path)
    case didLog(LogLevel, String)
  }

  func testHappyPath() throws {
    var didPerformActions = [Action]()
    let sut = AddArm64Simulator.live(
      lipoThin: .init { input, arch, output, _ in
        didPerformActions.append(.didLipoThin(input, arch, output))
      },
      lipoCrate: .init { input, output, _ in
        didPerformActions.append(.didLipoCreate(input, output))
      },
      arm64ToSim: { path in
        didPerformActions.append(.didArm64ToSim(path))
      },
      deletePath: .init { path, _ in
        didPerformActions.append(.didDeletePath(path))
      }
    )
    let deviceFramework = Path("device/Framework.framework")
    let simulatorFramework = Path("simulator/Framework.framework")
    let log = Log { level, message in
      didPerformActions.append(.didLog(level, message))
    }

    try sut(deviceFramework: deviceFramework, simulatorFramework: simulatorFramework, log)

    XCTAssertEqual(didPerformActions, [
      .didLog(.normal, "[AddArm64Simulator]"),
      .didLog(.verbose, "- deviceFramework: \(deviceFramework.string)"),
      .didLog(.verbose, "- simulatorFramework: \(simulatorFramework.string)"),
      .didLipoThin(Path("device/Framework.framework/Framework"), .arm64, Path("simulator/Framework.framework/Framework-arm64")),
      .didArm64ToSim("simulator/Framework.framework/Framework-arm64"),
      .didLipoCreate([Path("simulator/Framework.framework/Framework"), Path("simulator/Framework.framework/Framework-arm64")], Path("simulator/Framework.framework/Framework")),
      .didDeletePath(Path("simulator/Framework.framework/Framework-arm64"))
    ])
  }
}


================================================
FILE: Tests/XCFrameworkMakerTests/Actions/CopyFrameworkTests.swift
================================================
import XCTest
@testable import XCFrameworkMaker

final class CopyFrameworkTests: XCTestCase {
  enum Action: Equatable {
    case didCreateDir(Path)
    case didCopyPath(Path, Path)
    case didDeletePath(Path)
    case didLipoExtract(Path, [Arch], Path)
    case didLog(LogLevel, String)
  }

  func testHappyPath() throws {
    var didPerformActions = [Action]()
    let sut = CopyFramework.live(
      createDir: .init { path, _ in
        didPerformActions.append(.didCreateDir(path))
      },
      copyPath: .init { source, destination, _ in
        didPerformActions.append(.didCopyPath(source, destination))
      },
      deletePath: .init { path, _ in
        didPerformActions.append(.didDeletePath(path))
      },
      lipoExtract: .init { input, archs, output, _ in
        didPerformActions.append(.didLipoExtract(input, archs, output))
      }
    )
    let input = Path("input/Framework.framework")
    let archs = [Arch.i386, .arm64]
    let path = Path("output/path")
    let log = Log { level, message in
      didPerformActions.append(.didLog(level, message))
    }

    let output = try sut(input, archs: archs, path: path, log)

    XCTAssertEqual(didPerformActions, [
      .didLog(.normal, "[CopyFramework]"),
      .didLog(.verbose, "- input: \(input.string)"),
      .didLog(.verbose, "- archs: \(archs.map(\.rawValue).joined(separator: ", "))"),
      .didLog(.verbose, "- path: \(path.string)"),
      .didCreateDir(Path("output/path")),
      .didCopyPath(Path("input/Framework.framework"), Path("output/path/Framework.framework")),
      .didDeletePath(Path("output/path/Framework.framework/Framework")),
      .didLipoExtract(Path("input/Framework.framework/Framework"), [.i386, .arm64], Path("output/path/Framework.framework/Framework")),
      .didLog(.verbose, "- output: \(output.string)")
    ])
    XCTAssertEqual(output, path.addingComponent(input.lastComponent))
  }
}


================================================
FILE: Tests/XCFrameworkMakerTests/Actions/CopyPathTests.swift
================================================
import XCTest
@testable import XCFrameworkMaker

final class CopyPathTests: XCTestCase {
  enum Action: Equatable {
    case didRunShellCommand(String)
    case didLog(LogLevel, String)
  }

  func testHappyPath() throws {
    var didPerformActions = [Action]()
    let sut = CopyPath.live(runShellCommand: .init { command, _ in
      didPerformActions.append(.didRunShellCommand(command))
      return ""
    })
    let source = Path("source")
    let destination = Path("destination")
    let log = Log { level, message in
      didPerformActions.append(.didLog(level, message))
    }

    try sut(of: source, at: destination, log)

    XCTAssertEqual(didPerformActions, [
      .didLog(.normal, "[CopyPath]"),
      .didLog(.verbose, "- source: \(source.string)"),
      .didLog(.verbose, "- destination: \(destination.string)"),
      .didRunShellCommand("cp -fR source destination")
    ])
  }
}


================================================
FILE: Tests/XCFrameworkMakerTests/Actions/CreateDirTests.swift
================================================
import XCTest
@testable import XCFrameworkMaker

final class CreateDirTests: XCTestCase {
  enum Action: Equatable {
    case didRunShellCommand(String)
    case didLog(LogLevel, String)
  }

  func testHappyPath() throws {
    var didPerformActions = [Action]()
    let sut = CreateDir.live(runShellCommand: .init { command, _ in
      didPerformActions.append(.didRunShellCommand(command))
      return ""
    })
    let path = Path("new/directory/path")
    let log = Log { level, message in
      didPerformActions.append(.didLog(level, message))
    }

    try sut(path, log)

    XCTAssertEqual(didPerformActions, [
      .didLog(.normal, "[CreateDir]"),
      .didLog(.verbose, "- path: \(path.string)"),
      .didRunShellCommand("mkdir -p new/directory/path")
    ])
  }
}


================================================
FILE: Tests/XCFrameworkMakerTests/Actions/CreateTempDirTests.swift
================================================
import XCTest
@testable import XCFrameworkMaker

final class CreateTempDirTests: XCTestCase {
  enum Action: Equatable {
    case didCreateDir(Path)
    case didLog(LogLevel, String)
  }

  func testHappyPath() throws {
    var didPerformActions = [Action]()
    let basePath = "temp/dir/base/path"
    let randomString = "random"
    let sut = CreateTempDir.live(
      basePath: basePath,
      randomString: { randomString },
      createDir: .init { path, _ in
        didPerformActions.append(.didCreateDir(path))
      }
    )
    let log = Log { level, message in
      didPerformActions.append(.didLog(level, message))
    }

    let path = try sut(log)

    let expectedPath = Path(basePath).addingComponent("XCFrameworkMaker_\(randomString)")
    XCTAssertEqual(didPerformActions, [
      .didLog(.normal, "[CreateTempDir]"),
      .didCreateDir(expectedPath),
      .didLog(.verbose, "- path: \(path.string)")
    ])
    XCTAssertEqual(path, expectedPath)
  }
}


================================================
FILE: Tests/XCFrameworkMakerTests/Actions/CreateXCFrameworkTests.swift
================================================
import XCTest
@testable import XCFrameworkMaker

final class CreateXCFrameworkTests: XCTestCase {
  enum Action: Equatable {
    case didDeletePath(Path)
    case didRunShellCommand(String)
    case didLog(LogLevel, String)
  }

  func testHappyPath() throws {
    var didPerformActions = [Action]()
    let sut = CreateXCFramework.live(
      deletePath: .init { path, _ in
        didPerformActions.append(.didDeletePath(path))
      },
      runShellCommand: .init { command, _ in
        didPerformActions.append(.didRunShellCommand(command))
        return ""
      }
    )
    let frameworks = [
      Path("device/Framework.framework"),
      Path("simulator/Framework.framework")
    ]
    let path = Path("output/path")
    let log = Log { level, message in
      didPerformActions.append(.didLog(level, message))
    }

    try sut(from: frameworks, at: path, log)

    XCTAssertEqual(didPerformActions, [
      .didLog(.normal, "[CreateXCFramework]"),
      .didLog(.verbose, "- frameworks: \n\t\(frameworks.map(\.string).joined(separator: "\n\t"))"),
      .didLog(.verbose, "- path: \(path.string)"),
      .didDeletePath(Path("output/path/Framework.xcframework")),
      .didRunShellCommand("xcodebuild -create-xcframework -framework device/Framework.framework -framework simulator/Framework.framework -output output/path/Framework.xcframework")
    ])
  }
}


================================================
FILE: Tests/XCFrameworkMakerTests/Actions/DeletePathTests.swift
================================================
import XCTest
@testable import XCFrameworkMaker

final class DeletePathTests: XCTestCase {
  enum Action: Equatable {
    case didRunShellCommand(String)
    case didLog(LogLevel, String)
  }

  func testHappyPath() throws {
    var didPerformActions = [Action]()
    let sut = DeletePath.live(runShellCommand: .init { command, _ in
      didPerformActions.append(.didRunShellCommand(command))
      return ""
    })
    let path = Path("some/path")
    let log = Log { level, message in
      didPerformActions.append(.didLog(level, message))
    }

    try sut(path, log)

    XCTAssertEqual(didPerformActions, [
      .didLog(.normal, "[DeletePath]"),
      .didLog(.verbose, "- path: \(path.string)"),
      .didRunShellCommand("rm -Rf some/path")
    ])
  }
}


================================================
FILE: Tests/XCFrameworkMakerTests/Actions/GetArchsTests.swift
================================================
import XCTest
@testable import XCFrameworkMaker

final class GetArchsTests: XCTestCase {
  enum Action: Equatable {
    case didRunShellCommand(String)
    case didLog(LogLevel, String)
  }

  func testHappyPath() throws {
    var didPerformActions = [Action]()
    let sut = GetArchs.live(runShellCommand: .init { command, _ in
      didPerformActions.append(.didRunShellCommand(command))
      return "i386 arm64 unknown"
    })
    let frameworkPath = Path("path/to/Some.framework")
    let log = Log { level, message in
      didPerformActions.append(.didLog(level, message))
    }

    let archs = try sut(inFramework: frameworkPath, log)

    XCTAssertEqual(didPerformActions, [
      .didLog(.normal, "[GetArchs]"),
      .didLog(.verbose, "- frameworkPath: \(frameworkPath.string)"),
      .didRunShellCommand("lipo path/to/Some.framework/Some -archs"),
      .didLog(.verbose, "- archs: \(archs.map(\.rawValue).joined(separator: ", "))"),
    ])
    XCTAssertEqual(archs, [.i386, .arm64])
  }
}


================================================
FILE: Tests/XCFrameworkMakerTests/Actions/LipoCreateTests.swift
================================================
import XCTest
@testable import XCFrameworkMaker

final class LipoCreateTests: XCTestCase {
  enum Action: Equatable {
    case didRunShellCommand(String)
    case didLog(LogLevel, String)
  }

  func testHappyPath() throws {
    var didPerformActions = [Action]()
    let sut = LipoCreate.live(runShellCommand: .init { command, _ in
      didPerformActions.append(.didRunShellCommand(command))
      return ""
    })
    let inputs = [Path("input/file1"), Path("input/file2")]
    let output = Path("output/file")
    let log = Log { level, message in
      didPerformActions.append(.didLog(level, message))
    }

    try sut(inputs: inputs, output: output, log)

    XCTAssertEqual(didPerformActions, [
      .didLog(.normal, "[LipoCreate]"),
      .didLog(.verbose, "- inputs: \n\t\(inputs.map(\.string).joined(separator: "\n\t"))"),
      .didLog(.verbose, "- output: \(output.string)"),
      .didRunShellCommand("lipo input/file1 input/file2 -create -output output/file")
    ])
  }
}


================================================
FILE: Tests/XCFrameworkMakerTests/Actions/LipoExtractTests.swift
================================================
import XCTest
@testable import XCFrameworkMaker

final class LipoExtractTests: XCTestCase {
  enum Action: Equatable {
    case didRunShellCommand(String)
    case didLog(LogLevel, String)
  }

  func testHappyPath() throws {
    var didPerformActions = [Action]()
    let sut = LipoExtract.live(runShellCommand: .init { command, _ in
      didPerformActions.append(.didRunShellCommand(command))
      return ""
    })
    let input = Path("input/file")
    let archs = [Arch.i386, .arm64]
    let output = Path("output/file")
    let log = Log { level, message in
      didPerformActions.append(.didLog(level, message))
    }

    try sut(input: input, archs: archs, output: output, log)

    XCTAssertEqual(didPerformActions, [
      .didLog(.normal, "[LipoExtract]"),
      .didLog(.verbose, "- input: \(input.string)"),
      .didLog(.verbose, "- archs: \(archs.map(\.rawValue).joined(separator: ", "))"),
      .didLog(.verbose, "- output: \(input.string)"),
      .didRunShellCommand("lipo input/file -extract i386 -extract arm64 -output output/file")
    ])
  }
}


================================================
FILE: Tests/XCFrameworkMakerTests/Actions/LipoThinTests.swift
================================================
import XCTest
@testable import XCFrameworkMaker

final class LipoThinTests: XCTestCase {
  enum Action: Equatable {
    case didRunShellCommand(String)
    case didLog(LogLevel, String)
  }

  func testHappyPath() throws {
    var didPerformActions = [Action]()
    let sut = LipoThin.live(runShellCommand: .init { command, _ in
      didPerformActions.append(.didRunShellCommand(command))
      return ""
    })
    let input = Path("input/file")
    let arch = Arch.arm64
    let output = Path("output/file")
    let log = Log { level, message in
      didPerformActions.append(.didLog(level, message))
    }

    try sut(input: input, arch: arch, output: output, log)

    XCTAssertEqual(didPerformActions, [
      .didLog(.normal, "[LipoThin]"),
      .didLog(.verbose, "- input: \(input.string)"),
      .didLog(.verbose, "- arch: \(arch.rawValue)"),
      .didLog(.verbose, "- output: \(output.string)"),
      .didRunShellCommand("lipo input/file -thin arm64 -output output/file")
    ])
  }
}


================================================
FILE: Tests/XCFrameworkMakerTests/Actions/LogTests.swift
================================================
import XCTest
@testable import XCFrameworkMaker

final class LogTests: XCTestCase {
  func testNormalLogging() {
    var logged = [String]()
    let sut = Log.live(
      level: .normal,
      print: { logged.append($0) }
    )

    sut(.normal, "Normal level log")
    sut(.verbose, "Verbose level log")

    XCTAssertEqual(logged, ["Normal level log"])
  }

  func testVerboseLogging() {
    var logged = [String]()
    let sut = Log.live(
      level: .verbose,
      print: { logged.append($0) }
    )

    sut(.normal, "Normal level log")
    sut(.verbose, "Verbose level log")

    XCTAssertEqual(logged, [
      "Normal level log",
      "Verbose level log"
    ])
  }

  func testIndentedLogging() {
    var logged = [String]()
    let sut = Log.live(
      level: .normal,
      print: { logged.append($0) }
    ).indented()

    sut(.normal, "multiline\nlog\nmessage")

    XCTAssertEqual(logged, ["\tmultiline\n\tlog\n\tmessage"])
  }
}


================================================
FILE: Tests/XCFrameworkMakerTests/Actions/MakeXCFrameworkTests.swift
================================================
import XCTest
@testable import XCFrameworkMaker

final class MakeXCFrameworkTests: XCTestCase {
  enum Action: Equatable {
    case didCreateTempDir
    case didGetArchs(Path)
    case didCopyFramework(Path, [Arch], Path)
    case didAddArm64Simulator(Path, Path)
    case didCreateXCFramework([Path], Path)
    case didLog(LogLevel, String)
  }

  func testHappyPath() throws {
    var didPerformActions = [Action]()
    let iOSPath = Path("ios/Framework.framework")
    let tvOSPath = Path("tvos/Framework.framework")
    let createdTempDir = Path("temp/path")
    let archs: [Path: [Arch]] = [
      iOSPath: [.i386, .x86_64, .armv7, .arm64],
      tvOSPath: [.x86_64, .arm64]
    ]
    let copiedFrameworks: [Path: Path] = [
      iOSPath: Path("copy/ios/Framework.framework"),
      tvOSPath: Path("copy/tvos/Framework.framework")
    ]
    let sut = MakeXCFramework.live(
      createTempDir: .init { _ in
        didPerformActions.append(.didCreateTempDir)
        return createdTempDir
      },
      getArchs: .init { path, _ in
        didPerformActions.append(.didGetArchs(path))
        return archs[path]!
      },
      copyFramework: .init { input, archs, path, _ in
        didPerformActions.append(.didCopyFramework(input, archs, path))
        return copiedFrameworks[input]!
      },
      addArm64Simulator: .init { device, simulator, _ in
        didPerformActions.append(.didAddArm64Simulator(device, simulator))
      },
      createXCFramework: .init { frameworks, path, _ in
        didPerformActions.append(.didCreateXCFramework(frameworks, path))
      }
    )
    let output = Path("output/path")
    let log = Log { level, message in
      didPerformActions.append(.didLog(level, message))
    }

    try sut.callAsFunction(iOS: iOSPath, tvOS: tvOSPath, arm64sim: true, at: output, log)

    XCTAssertEqual(didPerformActions, [
      .didLog(.normal, "[MakeXCFramework]"),
      .didLog(.verbose, "- iOSPath: \(iOSPath.string)"),
      .didLog(.verbose, "- tvOSPath: \(tvOSPath.string)"),
      .didLog(.verbose, "- arm64sim: true"),
      .didLog(.verbose, "- output: \(output.string)"),

      .didCreateTempDir,

      .didGetArchs(iOSPath),
      .didCopyFramework(iOSPath, [.armv7, .arm64], createdTempDir.addingComponent("ios-device")),
      .didCopyFramework(iOSPath, [.i386, .x86_64], createdTempDir.addingComponent("ios-simulator")),
      .didAddArm64Simulator(copiedFrameworks[iOSPath]!, copiedFrameworks[iOSPath]!),

      .didGetArchs(tvOSPath),
      .didCopyFramework(tvOSPath, [.arm64], createdTempDir.addingComponent("tvos-device")),
      .didCopyFramework(tvOSPath, [.x86_64], createdTempDir.addingComponent("tvos-simulator")),
      .didAddArm64Simulator(copiedFrameworks[tvOSPath]!, copiedFrameworks[tvOSPath]!),

      .didCreateXCFramework([
        copiedFrameworks[iOSPath]!,
        copiedFrameworks[iOSPath]!,
        copiedFrameworks[tvOSPath]!,
        copiedFrameworks[tvOSPath]!
      ], output)
    ])
  }

  func testEmptyInputFailure() {
    let sut = MakeXCFramework.live(
      createTempDir: .init { _ in fatalError() },
      getArchs: .init { _, _ in fatalError() },
      copyFramework: .init { _, _, _, _ in fatalError() },
      createXCFramework: .init { _, _, _ in fatalError() }
    )
    var catchedError: Error?

    do { try sut(iOS: nil, tvOS: nil, arm64sim: true, at: Path("")) }
    catch { catchedError = error }

    XCTAssertEqual(catchedError as? MakeXCFramework.EmptyInputError, MakeXCFramework.EmptyInputError())
  }
}


================================================
FILE: Tests/XCFrameworkMakerTests/Actions/RunShellCommandTests.swift
================================================
import XCTest
@testable import XCFrameworkMaker

final class RunShellCommandTests: XCTestCase {
  enum Action: Equatable {
    case didShellOut(String)
    case didLog(LogLevel, String)
  }

  func testHappyPath() throws {
    var didPerformActions = [Action]()
    let shellOutput = "shell output"
    let sut = RunShellCommand.live(shellOut: { command in
      didPerformActions.append(.didShellOut(command))
      return shellOutput
    })
    let shellCommand = "shell command"
    let log = Log { level, message in
      didPerformActions.append(.didLog(level, message))
    }

    let result = try sut(shellCommand, log)

    XCTAssertEqual(didPerformActions, [
      .didLog(.normal, "[RunShellCommand]"),
      .didLog(.verbose, "- command: \(shellCommand)"),
      .didShellOut(shellCommand),
      .didLog(.verbose, "- output: \(shellOutput)")
    ])
    XCTAssertEqual(result, shellOutput)
  }
}


================================================
FILE: Tests/XCFrameworkMakerTests/Models/LogLevelTests.swift
================================================
import XCTest
@testable import XCFrameworkMaker

final class LogLevelTests: XCTestCase {
  func testComparable() {
    XCTAssertTrue(LogLevel.normal < LogLevel.verbose)
    XCTAssertTrue(LogLevel.normal <= LogLevel.verbose)
    XCTAssertFalse(LogLevel.normal > LogLevel.verbose)
    XCTAssertFalse(LogLevel.normal >= LogLevel.verbose)
  }
}


================================================
FILE: Tests/XCFrameworkMakerTests/Models/PathTests.swift
================================================
import XCTest
@testable import XCFrameworkMaker

final class PathTests: XCTestCase {
  func testAddingComponent() {
    XCTAssertEqual(Path("some/path").addingComponent("component").string, "some/path/component")
    XCTAssertEqual(Path("some/path/").addingComponent("component").string, "some/path/component")
  }

  func testLastComponent() {
    XCTAssertEqual(Path("some/file").lastComponent, "file")
    XCTAssertEqual(Path("some/file.extension").lastComponent, "file.extension")
    XCTAssertEqual(Path("some/directory/").lastComponent, "directory")
    XCTAssertEqual(Path("path").lastComponent, "path")
    XCTAssertEqual(Path("").lastComponent, "")
    XCTAssertEqual(Path("/").lastComponent, "")
    XCTAssertEqual(Path("//").lastComponent, "")
    XCTAssertEqual(Path("path/").lastComponent, "path")
    XCTAssertEqual(Path("path//").lastComponent, "path")
    XCTAssertEqual(Path("/path/").lastComponent, "path")
    XCTAssertEqual(Path("some/path///").lastComponent, "path")
  }

  func testFileExtension() {
    XCTAssertNil(Path("file").fileExtension)
    XCTAssertNil(Path("path/to/some/file").fileExtension)
    XCTAssertEqual(Path("file.ext").fileExtension, "ext")
    XCTAssertEqual(Path("file.name.ext").fileExtension, "ext")
    XCTAssertEqual(Path("path/to/file.ext").fileExtension, "ext")
    XCTAssertEqual(Path("/path/to/file.ext").fileExtension, "ext")
    XCTAssertEqual(Path("path/to/file.ext/").fileExtension, "ext")
    XCTAssertEqual(Path("/path/to/file.ext//").fileExtension, "ext")
  }

  func testFilenameExcludingExtension() {
    XCTAssertEqual(Path("file").filenameExcludingExtension, "file")
    XCTAssertEqual(Path("file.ext").filenameExcludingExtension, "file")
    XCTAssertEqual(Path("file.name.ext").filenameExcludingExtension, "file.name")
    XCTAssertEqual(Path("path/to/file.ext").filenameExcludingExtension, "file")
    XCTAssertEqual(Path("/path/to/file.ext").filenameExcludingExtension, "file")
    XCTAssertEqual(Path("path/to/file.ext/").filenameExcludingExtension, "file")
    XCTAssertEqual(Path("/path/to/file.ext//").filenameExcludingExtension, "file")
  }
}
Download .txt
gitextract_2cuer62l/

├── .gitignore
├── .swiftpm/
│   └── xcode/
│       └── xcshareddata/
│           └── xcschemes/
│               ├── XCFrameworkMaker.xcscheme
│               └── make-xcframework.xcscheme
├── LICENSE
├── Package.resolved
├── Package.swift
├── README.md
├── Sources/
│   ├── XCFrameworkMaker/
│   │   ├── Actions/
│   │   │   ├── AddArm64Simulator.swift
│   │   │   ├── CopyFramework.swift
│   │   │   ├── CopyPath.swift
│   │   │   ├── CreateDir.swift
│   │   │   ├── CreateTempDir.swift
│   │   │   ├── CreateXCFramework.swift
│   │   │   ├── DeletePath.swift
│   │   │   ├── GetArchs.swift
│   │   │   ├── LipoCreate.swift
│   │   │   ├── LipoExtract.swift
│   │   │   ├── LipoThin.swift
│   │   │   ├── Log.swift
│   │   │   ├── MakeXCFramework.swift
│   │   │   └── RunShellCommand.swift
│   │   └── Models/
│   │       ├── Arch.swift
│   │       ├── LogLevel.swift
│   │       └── Path.swift
│   └── make-xcframework/
│       ├── MainCommand.swift
│       └── main.swift
└── Tests/
    └── XCFrameworkMakerTests/
        ├── Actions/
        │   ├── AddArm64SimulatorTests.swift
        │   ├── CopyFrameworkTests.swift
        │   ├── CopyPathTests.swift
        │   ├── CreateDirTests.swift
        │   ├── CreateTempDirTests.swift
        │   ├── CreateXCFrameworkTests.swift
        │   ├── DeletePathTests.swift
        │   ├── GetArchsTests.swift
        │   ├── LipoCreateTests.swift
        │   ├── LipoExtractTests.swift
        │   ├── LipoThinTests.swift
        │   ├── LogTests.swift
        │   ├── MakeXCFrameworkTests.swift
        │   └── RunShellCommandTests.swift
        └── Models/
            ├── LogLevelTests.swift
            └── PathTests.swift
Condensed preview — 42 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (63K chars).
[
  {
    "path": ".gitignore",
    "chars": 126,
    "preview": ".DS_Store\n/.build\n/Packages\n/*.xcodeproj\nxcuserdata/\nDerivedData/\n.swiftpm/xcode/package.xcworkspace/contents.xcworkspac"
  },
  {
    "path": ".swiftpm/xcode/xcshareddata/xcschemes/XCFrameworkMaker.xcscheme",
    "chars": 2802,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1250\"\n   version = \"1.3\">\n   <BuildAction\n      "
  },
  {
    "path": ".swiftpm/xcode/xcshareddata/xcschemes/make-xcframework.xcscheme",
    "chars": 3228,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1250\"\n   version = \"1.3\">\n   <BuildAction\n      "
  },
  {
    "path": "LICENSE",
    "chars": 1082,
    "preview": "MIT License\n\nCopyright (c) 2021 Dariusz Rybicki Darrarski\n\nPermission is hereby granted, free of charge, to any person o"
  },
  {
    "path": "Package.resolved",
    "chars": 893,
    "preview": "{\n  \"object\": {\n    \"pins\": [\n      {\n        \"package\": \"arm64-to-sim\",\n        \"repositoryURL\": \"https://github.com/da"
  },
  {
    "path": "Package.swift",
    "chars": 1500,
    "preview": "// swift-tools-version:5.4\nimport PackageDescription\n\nlet package = Package(\n  name: \"xcframework-maker\",\n  platforms: ["
  },
  {
    "path": "README.md",
    "chars": 4397,
    "preview": "# xcframework-maker\n\n![swift 5.4](https://img.shields.io/badge/swift-5.4-orange.svg)\n![platform macOS](https://img.shiel"
  },
  {
    "path": "Sources/XCFrameworkMaker/Actions/AddArm64Simulator.swift",
    "chars": 1647,
    "preview": "import Arm64ToSim\n\n/// Adds arm64 simulator support to a framework\npublic struct AddArm64Simulator {\n  var run: (Path, P"
  },
  {
    "path": "Sources/XCFrameworkMaker/Actions/CopyFramework.swift",
    "chars": 1726,
    "preview": "/// Creates copy of a framework with provided architectures\npublic struct CopyFramework {\n  var run: (Path, [Arch], Path"
  },
  {
    "path": "Sources/XCFrameworkMaker/Actions/CopyPath.swift",
    "chars": 881,
    "preview": "/// Creates copy of file or directory\npublic struct CopyPath {\n  var run: (Path, Path, Log?) throws -> Void\n\n  /// Creat"
  },
  {
    "path": "Sources/XCFrameworkMaker/Actions/CreateDir.swift",
    "chars": 680,
    "preview": "/// Creates directory\npublic struct CreateDir {\n  var run: (Path, Log?) throws -> Void\n\n  /// Create directory at provie"
  },
  {
    "path": "Sources/XCFrameworkMaker/Actions/CreateTempDir.swift",
    "chars": 903,
    "preview": "import Foundation\n\n/// Creates new temporary directory\npublic struct CreateTempDir {\n  var run: (Log?) throws -> Path\n\n "
  },
  {
    "path": "Sources/XCFrameworkMaker/Actions/CreateXCFramework.swift",
    "chars": 1391,
    "preview": "/// Creates XCFramework from provided thin frameworks\npublic struct CreateXCFramework {\n  var run: ([Path], Path, Log?) "
  },
  {
    "path": "Sources/XCFrameworkMaker/Actions/DeletePath.swift",
    "chars": 689,
    "preview": "/// Deletes file or directory\npublic struct DeletePath {\n  var run: (Path, Log?) throws -> Void\n\n  /// Delete file or di"
  },
  {
    "path": "Sources/XCFrameworkMaker/Actions/GetArchs.swift",
    "chars": 1164,
    "preview": "/// Gets architectures contained in a framework\npublic struct GetArchs {\n  var run: (Path, Log?) throws -> [Arch]\n\n  ///"
  },
  {
    "path": "Sources/XCFrameworkMaker/Actions/LipoCreate.swift",
    "chars": 980,
    "preview": "/// Use lipo to create binary file from other binary files\npublic struct LipoCreate {\n  var run: ([Path], Path, Log?) th"
  },
  {
    "path": "Sources/XCFrameworkMaker/Actions/LipoExtract.swift",
    "chars": 1150,
    "preview": "/// Use lipo to extract provided architectures from binary file\npublic struct LipoExtract {\n  var run: (Path, [Arch], Pa"
  },
  {
    "path": "Sources/XCFrameworkMaker/Actions/LipoThin.swift",
    "chars": 1070,
    "preview": "/// Use lipo to create thin binary file with provided architecture\npublic struct LipoThin {\n  var run: (Path, Arch, Path"
  },
  {
    "path": "Sources/XCFrameworkMaker/Actions/Log.swift",
    "chars": 947,
    "preview": "/// Logs messages\npublic struct Log {\n  var run: (LogLevel, String) -> Void\n\n  /// Log message\n  /// - Parameters:\n  ///"
  },
  {
    "path": "Sources/XCFrameworkMaker/Actions/MakeXCFramework.swift",
    "chars": 3687,
    "preview": "import Foundation\n\n/// Creates XCFramework from provided fat frameworks\npublic struct MakeXCFramework {\n  var run: (Path"
  },
  {
    "path": "Sources/XCFrameworkMaker/Actions/RunShellCommand.swift",
    "chars": 821,
    "preview": "import ShellOut\n\n/// Execute shell command\npublic struct RunShellCommand {\n  var run: (String, Log?) throws -> String\n\n "
  },
  {
    "path": "Sources/XCFrameworkMaker/Models/Arch.swift",
    "chars": 81,
    "preview": "public enum Arch: String {\n  case i386\n  case x86_64\n  case armv7\n  case arm64\n}\n"
  },
  {
    "path": "Sources/XCFrameworkMaker/Models/LogLevel.swift",
    "chars": 249,
    "preview": "public enum LogLevel: Equatable, CaseIterable {\n  case normal\n  case verbose\n}\n\nextension LogLevel: Comparable {\n  publi"
  },
  {
    "path": "Sources/XCFrameworkMaker/Models/Path.swift",
    "chars": 1090,
    "preview": "import Foundation\n\npublic struct Path: Equatable, Hashable {\n  public init(_ string: String) {\n    self.string = string\n"
  },
  {
    "path": "Sources/make-xcframework/MainCommand.swift",
    "chars": 3048,
    "preview": "import ArgumentParser\nimport Foundation\nimport XCFrameworkMaker\n\nstruct MainCommand: ParsableCommand {\n  static var make"
  },
  {
    "path": "Sources/make-xcframework/main.swift",
    "chars": 19,
    "preview": "MainCommand.main()\n"
  },
  {
    "path": "Tests/XCFrameworkMakerTests/Actions/AddArm64SimulatorTests.swift",
    "chars": 1878,
    "preview": "import XCTest\n@testable import XCFrameworkMaker\n\nfinal class AddArm64SimulatorTests: XCTestCase {\n  enum Action: Equatab"
  },
  {
    "path": "Tests/XCFrameworkMakerTests/Actions/CopyFrameworkTests.swift",
    "chars": 1909,
    "preview": "import XCTest\n@testable import XCFrameworkMaker\n\nfinal class CopyFrameworkTests: XCTestCase {\n  enum Action: Equatable {"
  },
  {
    "path": "Tests/XCFrameworkMakerTests/Actions/CopyPathTests.swift",
    "chars": 901,
    "preview": "import XCTest\n@testable import XCFrameworkMaker\n\nfinal class CopyPathTests: XCTestCase {\n  enum Action: Equatable {\n    "
  },
  {
    "path": "Tests/XCFrameworkMakerTests/Actions/CreateDirTests.swift",
    "chars": 782,
    "preview": "import XCTest\n@testable import XCFrameworkMaker\n\nfinal class CreateDirTests: XCTestCase {\n  enum Action: Equatable {\n   "
  },
  {
    "path": "Tests/XCFrameworkMakerTests/Actions/CreateTempDirTests.swift",
    "chars": 973,
    "preview": "import XCTest\n@testable import XCFrameworkMaker\n\nfinal class CreateTempDirTests: XCTestCase {\n  enum Action: Equatable {"
  },
  {
    "path": "Tests/XCFrameworkMakerTests/Actions/CreateXCFrameworkTests.swift",
    "chars": 1373,
    "preview": "import XCTest\n@testable import XCFrameworkMaker\n\nfinal class CreateXCFrameworkTests: XCTestCase {\n  enum Action: Equatab"
  },
  {
    "path": "Tests/XCFrameworkMakerTests/Actions/DeletePathTests.swift",
    "chars": 765,
    "preview": "import XCTest\n@testable import XCFrameworkMaker\n\nfinal class DeletePathTests: XCTestCase {\n  enum Action: Equatable {\n  "
  },
  {
    "path": "Tests/XCFrameworkMakerTests/Actions/GetArchsTests.swift",
    "chars": 1004,
    "preview": "import XCTest\n@testable import XCFrameworkMaker\n\nfinal class GetArchsTests: XCTestCase {\n  enum Action: Equatable {\n    "
  },
  {
    "path": "Tests/XCFrameworkMakerTests/Actions/LipoCreateTests.swift",
    "chars": 991,
    "preview": "import XCTest\n@testable import XCFrameworkMaker\n\nfinal class LipoCreateTests: XCTestCase {\n  enum Action: Equatable {\n  "
  },
  {
    "path": "Tests/XCFrameworkMakerTests/Actions/LipoExtractTests.swift",
    "chars": 1071,
    "preview": "import XCTest\n@testable import XCFrameworkMaker\n\nfinal class LipoExtractTests: XCTestCase {\n  enum Action: Equatable {\n "
  },
  {
    "path": "Tests/XCFrameworkMakerTests/Actions/LipoThinTests.swift",
    "chars": 1001,
    "preview": "import XCTest\n@testable import XCFrameworkMaker\n\nfinal class LipoThinTests: XCTestCase {\n  enum Action: Equatable {\n    "
  },
  {
    "path": "Tests/XCFrameworkMakerTests/Actions/LogTests.swift",
    "chars": 948,
    "preview": "import XCTest\n@testable import XCFrameworkMaker\n\nfinal class LogTests: XCTestCase {\n  func testNormalLogging() {\n    var"
  },
  {
    "path": "Tests/XCFrameworkMakerTests/Actions/MakeXCFrameworkTests.swift",
    "chars": 3506,
    "preview": "import XCTest\n@testable import XCFrameworkMaker\n\nfinal class MakeXCFrameworkTests: XCTestCase {\n  enum Action: Equatable"
  },
  {
    "path": "Tests/XCFrameworkMakerTests/Actions/RunShellCommandTests.swift",
    "chars": 907,
    "preview": "import XCTest\n@testable import XCFrameworkMaker\n\nfinal class RunShellCommandTests: XCTestCase {\n  enum Action: Equatable"
  },
  {
    "path": "Tests/XCFrameworkMakerTests/Models/LogLevelTests.swift",
    "chars": 341,
    "preview": "import XCTest\n@testable import XCFrameworkMaker\n\nfinal class LogLevelTests: XCTestCase {\n  func testComparable() {\n    X"
  },
  {
    "path": "Tests/XCFrameworkMakerTests/Models/PathTests.swift",
    "chars": 2115,
    "preview": "import XCTest\n@testable import XCFrameworkMaker\n\nfinal class PathTests: XCTestCase {\n  func testAddingComponent() {\n    "
  }
]

About this extraction

This page contains the full source code of the darrarski/xcframework-maker GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 42 files (55.4 KB), approximately 15.5k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!