From 954e878a58839a419071e5935deba90f0a117c9c Mon Sep 17 00:00:00 2001 From: Werner Altewischer Date: Tue, 5 Nov 2019 15:24:48 +0100 Subject: [PATCH 1/2] Added caching for commonly used commands --- Source/CarthageKit/SwiftToolchain.swift | 25 ++++++++---- Source/CarthageKit/Xcode.swift | 52 ++++++++++++++----------- 2 files changed, 46 insertions(+), 31 deletions(-) diff --git a/Source/CarthageKit/SwiftToolchain.swift b/Source/CarthageKit/SwiftToolchain.swift index fc8ad656..7d792883 100644 --- a/Source/CarthageKit/SwiftToolchain.swift +++ b/Source/CarthageKit/SwiftToolchain.swift @@ -8,6 +8,8 @@ import struct Foundation.URL /// Swift compiler helper methods public final class SwiftToolchain { + private static let swiftVersionCache = Cache>() + internal static var swiftVersionRegex: NSRegularExpression = try! NSRegularExpression(pattern: "Apple Swift version ([^\\s]+) .*\\((.[^\\)]+)\\)", options: []) /// Emits the currect Swift version @@ -53,15 +55,22 @@ public final class SwiftToolchain { /// Attempts to determine the local version of swift private static func determineSwiftVersion(usingToolchain toolchain: String?) -> SignalProducer { - let taskDescription = Task("/usr/bin/env", arguments: compilerVersionArguments(usingToolchain: toolchain)) + + let result = swiftVersionCache.getValue(key: toolchain) { toolchain in + + let taskDescription = Task("/usr/bin/env", arguments: compilerVersionArguments(usingToolchain: toolchain)) - return taskDescription.launch(standardInput: nil) - .ignoreTaskData() - .mapError { _ in SwiftVersionError.unknownLocalSwiftVersion } - .map { data -> String? in - return parseSwiftVersionCommand(output: String(data: data, encoding: .utf8)) - } - .attemptMap { Result($0, failWith: SwiftVersionError.unknownLocalSwiftVersion) } + return taskDescription.launch(standardInput: nil) + .ignoreTaskData() + .mapError { _ in SwiftVersionError.unknownLocalSwiftVersion } + .map { data -> String? in + return parseSwiftVersionCommand(output: String(data: data, encoding: .utf8)) + } + .attemptMap { Result($0, failWith: SwiftVersionError.unknownLocalSwiftVersion) } + .first()! + } + + return SignalProducer(result: result) } private static func compilerVersionArguments(usingToolchain toolchain: String?) -> [String] { diff --git a/Source/CarthageKit/Xcode.swift b/Source/CarthageKit/Xcode.swift index 6f945105..8cf77b58 100644 --- a/Source/CarthageKit/Xcode.swift +++ b/Source/CarthageKit/Xcode.swift @@ -19,6 +19,7 @@ public final class Xcode { private static let buildSettingsCache = Cache>() private static let schemeNamesCache = Cache>() + private static let destinationsCache = Cache>() /// Attempts to build the dependency, then places its build product into the /// root directory given. @@ -820,27 +821,20 @@ public final class Xcode { return SignalProducer(error: error) } } - - /// Runs the build for a given sdk and build arguments, optionally performing a clean first - // swiftlint:disable:next static function_body_length - private static func build(sdk: SDK, with buildArgs: BuildArguments, in workingDirectoryURL: URL) -> SignalProducer, CarthageError> { - var argsForLoading = buildArgs - argsForLoading.sdk = sdk - - var argsForBuilding = argsForLoading - argsForBuilding.onlyActiveArchitecture = false - - // If SDK is the iOS simulator, then also find and set a valid destination. - // This fixes problems when the project deployment version is lower than - // the target's one and includes simulators unsupported by the target. - // - // Example: Target is at 8.0, project at 7.0, xcodebuild chooses the first - // simulator on the list, iPad 2 7.1, which is invalid for the target. - // - // See https://github.com/Carthage/Carthage/issues/417. - func fetchDestination() -> SignalProducer { - // Specifying destination seems to be required for building with - // simulator SDKs since Xcode 7.2. + + // If SDK is the iOS simulator, then also find and set a valid destination. + // This fixes problems when the project deployment version is lower than + // the target's one and includes simulators unsupported by the target. + // + // Example: Target is at 8.0, project at 7.0, xcodebuild chooses the first + // simulator on the list, iPad 2 7.1, which is invalid for the target. + // + // See https://github.com/Carthage/Carthage/issues/417. + private static func fetchDestination(sdk: SDK) -> SignalProducer { + // Specifying destination seems to be required for building with + // simulator SDKs since Xcode 7.2. + + let result = destinationsCache.getValue(key: sdk) { sdk -> Result in if sdk.isSimulator { let destinationLookup = Task("/usr/bin/xcrun", arguments: [ "simctl", "list", "devices", "--json" ]) return destinationLookup.launch() @@ -854,11 +848,23 @@ public final class Xcode { } } .map { "platform=\(sdk.platform.rawValue) Simulator,id=\($0.udid.uuidString)" } + .first()! } - return SignalProducer(value: nil) + return .success(nil) } + return SignalProducer(result: result) + } + + /// Runs the build for a given sdk and build arguments, optionally performing a clean first + // swiftlint:disable:next static function_body_length + private static func build(sdk: SDK, with buildArgs: BuildArguments, in workingDirectoryURL: URL) -> SignalProducer, CarthageError> { + var argsForLoading = buildArgs + argsForLoading.sdk = sdk + + var argsForBuilding = argsForLoading + argsForBuilding.onlyActiveArchitecture = false - return fetchDestination() + return fetchDestination(sdk: sdk) .flatMap(.concat) { destination -> SignalProducer, CarthageError> in if let destination = destination { argsForBuilding.destination = destination From c1e0ea54a358d39a3b4912db52846dcdce6420c2 Mon Sep 17 00:00:00 2001 From: Werner Altewischer Date: Wed, 6 Nov 2019 09:21:19 +0100 Subject: [PATCH 2/2] Updated README, version and Makefile --- Makefile | 14 +- README.md | 185 ++++++++++---------- Source/CarthageKit/CarthageKitVersion.swift | 2 +- 3 files changed, 101 insertions(+), 100 deletions(-) diff --git a/Makefile b/Makefile index 217373e6..3a5343f9 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,11 @@ #!/usr/bin/xcrun make -f -CARTHAGE_TEMPORARY_FOLDER?=/tmp/Carthage.dst +CARTHAGE_TEMPORARY_FOLDER?=/tmp/Carthage++.dst PREFIX?=/usr/local CONFIGURATION?=release INTERNAL_PACKAGE=CarthageApp.pkg -OUTPUT_PACKAGE=Carthage.pkg +OUTPUT_PACKAGE=Carthage++.pkg CARTHAGE_EXECUTABLE=./.build/$(CONFIGURATION)/carthage BINARIES_FOLDER=/usr/local/bin @@ -58,10 +58,10 @@ installables: package: installables $(MKDIR) "$(CARTHAGE_TEMPORARY_FOLDER)$(BINARIES_FOLDER)" - $(CP) "$(CARTHAGE_EXECUTABLE)" "$(CARTHAGE_TEMPORARY_FOLDER)$(BINARIES_FOLDER)" + $(CP) "$(CARTHAGE_EXECUTABLE)" "$(CARTHAGE_TEMPORARY_FOLDER)$(BINARIES_FOLDER)/carthage++" pkgbuild \ - --identifier "org.carthage.carthage" \ + --identifier "org.carthage.carthage++" \ --install-location "/" \ --root "$(CARTHAGE_TEMPORARY_FOLDER)" \ --version "$(VERSION_STRING)" \ @@ -74,13 +74,13 @@ package: installables prefix_install: installables $(MKDIR) "$(PREFIX)/bin" - $(CP) -f "$(CARTHAGE_EXECUTABLE)" "$(PREFIX)/bin/" + $(CP) -f "$(CARTHAGE_EXECUTABLE)" "$(PREFIX)/bin/carthage++" install: installables - $(SUDO) $(CP) -f "$(CARTHAGE_EXECUTABLE)" "$(BINARIES_FOLDER)" + $(SUDO) $(CP) -f "$(CARTHAGE_EXECUTABLE)" "$(BINARIES_FOLDER)/carthage++" uninstall: - $(RM) "$(BINARIES_FOLDER)/carthage" + $(RM) "$(BINARIES_FOLDER)/carthage++" .build/libSwiftPM.xcconfig: mkdir -p .build diff --git a/README.md b/README.md index 6e1d1988..ef13f4d6 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ ![](Logo/PNG/header.png) -# Carthage [![GitHub license](https://img.shields.io/badge/license-MIT-lightgrey.svg)](https://raw.githubusercontent.com/nsoperations/Carthage/master/LICENSE.md) [![GitHub release](https://img.shields.io/github/release/nsoperations/carthage.svg)](https://github.com/nsoperations/Carthage/releases) [![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com) +# Carthage++ [![GitHub license](https://img.shields.io/badge/license-MIT-lightgrey.svg)](https://raw.githubusercontent.com/nsoperations/Carthage/master/LICENSE.md) [![GitHub release](https://img.shields.io/github/release/nsoperations/carthage.svg)](https://github.com/nsoperations/Carthage/releases) [![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com) -Carthage is intended to be the simplest way to add frameworks to your Cocoa application. +Carthage++ is intended to be the simplest way to add frameworks to your Cocoa application. -Carthage builds your dependencies and provides you with binary frameworks, but you retain full control over your project structure and setup. Carthage does not automatically modify your project files or your build settings. +Carthage++ builds your dependencies and provides you with binary frameworks, but you retain full control over your project structure and setup. Carthage++ does not automatically modify your project files or your build settings. -This is a fork on the official [Carthage](https://github.com/Carthage/Carthage) which fixes a lot of issues, most importantly: +This project started out as a fork of [Carthage](https://github.com/Carthage/Carthage), fixing a lot of bugs and improving caching features. Since then, the code has diverged so much that it deserves to be a separate project in its own right, hence Carthage++. Primarily Carthage++ adds the following on top of Carthage: - Fixes resolver issues: replaces both the original and new resolver with a completely rewritten resolver which passes all (performance) tests. Also added a lot more tests based on JSON fixtures for problematic dependency trees. The flag --new-resolver does not exist anymore. -- Adds the carthage `diagnose` command for creating new test fixtures for problematic dependency trees. +- Adds the `diagnose` command for creating new test fixtures for problematic dependency trees. - Fixes concurrency issues: all file system actions upon potentially shared resource (checkout cache, derived data folder, binaries cache, etc) are now protected with locks based on the system utility shlock. This ensures that CI systems can run multiple Carthage jobs in parallel. An option `--lock-timeout` has been added to relevant commands to specify a custom time-out in seconds for acquiring locks (default is no time-out). - Fixes the DWARFs symbol problem for pre-built cached binaries by automatically creating mapping plists in the dSYM bundles for the relevant sources. This allows for debugging Carthage dependencies which were not built on the developer machine. - Adds a plugable caching mechanism, enabled by the option `--cache-command` for all build-related commands. A custom shell script or executable can be specified to retrieve cached binaries from arbitrary back-ends. The CARTHAGE_CACHE_COMMAND environment variable is used as a default for this command. If not defined, a fall back to the original GitHub API based caching will take place. @@ -18,20 +18,21 @@ This is a fork on the official [Carthage](https://github.com/Carthage/Carthage) - Adds support for automatic discovery of frameworks to copy using the `--auto` flag for the `copy-frameworks` command. - Adds support for local storage of binary builds in the carthage binaries cache when the build option `--use-binaries` is enabled (which is the default). - Adds support for automatic rebuilding of cached dependencies when local changes have been made using the build option `--track-local-changes` +- Adds support for authentication via .netrc for binary dependencies See [this video](https://youtu.be/21nbRGpy3xM) for an overview and some demos. To install: -`brew tap nsoperations/formulas && brew install nsoperations/formulas/carthage` +`brew install carthage++` -See [Installing Carthage](#installing-carthage) +See [Installing Carthage++](#installing-carthage) ## Contents - [Change Log](#change-log) - [Quick Start](#quick-start) -- [Installing Carthage](#installing-carthage) +- [Installing Carthage++](#installing-carthage++) - [Adding frameworks to an application](#adding-frameworks-to-an-application) - [Getting started](#getting-started) - [If you're building for macOS](#if-youre-building-for-macos) @@ -39,7 +40,7 @@ See [Installing Carthage](#installing-carthage) - [For both platforms](#for-both-platforms) - [(Optionally) Add build phase to warn about outdated dependencies](#optionally-add-build-phase-to-warn-about-outdated-dependencies) - [Swift binary framework download compatibility](#swift-binary-framework-download-compatibility) - - [Running a project that uses Carthage](#running-a-project-that-uses-carthage) + - [Running a project that uses Carthage++](#running-a-project-that-uses-carthage++) - [Adding frameworks to unit tests or a framework](#adding-frameworks-to-unit-tests-or-a-framework) - [Upgrading frameworks](#upgrading-frameworks) - [Diagnosing resolver problems](#diagnosing-resolver-problems) @@ -48,7 +49,7 @@ See [Installing Carthage](#installing-carthage) - [Automatically rebuilding dependencies](#automatically-rebuilding-dependencies) - [Caching builds](#caching-builds) - [Bash/Zsh/Fish completion](#bashzshfish-completion) -- [Supporting Carthage for your framework](#supporting-carthage-for-your-framework) +- [Supporting Carthage++ for your framework](#supporting-carthage++-for-your-framework) - [Share your Xcode schemes](#share-your-xcode-schemes) - [Filter discoverable schemes](#filter-discoverable-schemes) - [Resolve build failures](#resolve-build-failures) @@ -58,7 +59,7 @@ See [Installing Carthage](#installing-carthage) - [Build static frameworks to speed up your app’s launch times](#build-static-frameworks-to-speed-up-your-apps-launch-times) - [Declare your compatibility](#declare-your-compatibility) - [CarthageKit](#carthagekit) -- [Differences between Carthage and CocoaPods](#differences-between-carthage-and-cocoapods) +- [Differences between Carthage++ and CocoaPods](#differences-between-carthage++-and-cocoapods) - [License](#license) ## Change Log @@ -160,7 +161,7 @@ Up-to-date with version 0.33.0 of the original Carthage. Additionally it contain ## Quick Start -1. Get Carthage by running `brew tap nsoperations/formulas && brew install nsoperations/formulas/carthage` or choose [another installation method](#installing-carthage) +1. Get Carthage++ by running `brew install carthage++` or choose [another installation method](#installing-carthage++) 1. Create a [Cartfile][] in the same directory where your `.xcodeproj` or `.xcworkspace` is 1. List the desired dependencies in the [Cartfile][], for example: @@ -168,17 +169,17 @@ Up-to-date with version 0.33.0 of the original Carthage. Additionally it contain github "Alamofire/Alamofire" ~> 4.7.2 ``` -1. Run `carthage update` +1. Run `carthage++ update` 1. A `Cartfile.resolved` file and a `Carthage` directory will appear in the same directory where your `.xcodeproj` or `.xcworkspace` is 1. Drag the built `.framework` binaries from `Carthage/Build/` into your application’s Xcode project. -1. If you are using Carthage for an application, follow the remaining steps, otherwise stop here. +1. If you are using Carthage++ for an application, follow the remaining steps, otherwise stop here. 1. On your application targets’ _Build Phases_ settings tab, click the _+_ icon and choose _New Run Script Phase_. Create a Run Script in which you specify your shell (ex: `/bin/sh`), add the following contents to the script area below the shell: ```sh - /usr/local/bin/carthage copy-frameworks --auto + carthage++ copy-frameworks --auto ``` -From that point all of the Carthage's frameworks that are linked againts your target will be copied automatically. +From that point all of the Carthage++'s frameworks that are linked againts your target will be copied automatically. In case you need to specify path to your framework manually for whatever reason, do: @@ -196,26 +197,26 @@ In case you need to specify path to your framework manually for whatever reason, For an in depth guide, read on from [Adding frameworks to an application](#adding-frameworks-to-an-application) -## Installing Carthage +## Installing Carthage++ -There are multiple options for installing Carthage: +There are multiple options for installing Carthage++: * **Installer:** Download and run the `Carthage.pkg` file for the latest [release](https://github.com/nsoperations/Carthage/releases), then follow the on-screen instructions. If you are installing the pkg via CLI, you might need to run `sudo chown -R $(whoami) /usr/local` first. -* **Homebrew:** You can use [Homebrew](http://brew.sh) and install the `carthage` tool on your system. Since this is a fork you need to first tap the forked formula by `brew tap nsoperations/formulas`. Then run simply run `brew update` and `brew install -s nsoperations/formulas/carthage`. (note: if you previously installed the binary version of Carthage, you should delete `/Library/Frameworks/CarthageKit.framework`. If you installed the official carthage via brew, first remove it via `brew uninstall carthage`). +* **Homebrew:** You can use [Homebrew](http://brew.sh) and install the `carthage++` tool on your system. Simply run `brew install carthage++`. (note: if you previously installed the binary version of Carthage++, you should delete `/Library/Frameworks/CarthageKit.framework`. * **From source:** If you’d like to run the latest development version (which may be highly unstable or incompatible), simply clone the `master` branch of the repository, then run `make install` or `make prefix_install PREFIX=""`. Requires Xcode 9.4 (Swift 4.1). ## Adding frameworks to an application -Once you have Carthage [installed](#installing-carthage), you can begin adding frameworks to your project. Note that Carthage only supports dynamic frameworks, which are **only available on iOS 8 or later** (or any version of OS X). +Once you have Carthage++ [installed](#installing-carthage++), you can begin adding frameworks to your project. Note that Carthage++ only supports dynamic frameworks, which are **only available on iOS 8 or later** (or any version of OS X). ### Getting started ##### If you're building for macOS 1. Create a [Cartfile][] that lists the frameworks you’d like to use in your project. -1. Run `carthage update --platform macOS`. This will fetch dependencies into a [Carthage/Checkouts][] folder and build each one or download a pre-compiled framework. +1. Run `carthage++ update --platform macOS`. This will fetch dependencies into a [Carthage/Checkouts][] folder and build each one or download a pre-compiled framework. 1. On your application targets’ _General_ settings tab, in the _Embedded Binaries_ section, drag and drop each framework you want to use from the [Carthage/Build][] folder on disk. Additionally, you'll need to copy debug symbols for debugging and crash reporting on OS X. @@ -227,24 +228,24 @@ Additionally, you'll need to copy debug symbols for debugging and crash reportin ##### If you're building for iOS, tvOS, or watchOS 1. Create a [Cartfile][] that lists the frameworks you’d like to use in your project. -1. Run `carthage update`. This will fetch dependencies into a [Carthage/Checkouts][] folder, then build each one or download a pre-compiled framework. +1. Run `carthage++ update`. This will fetch dependencies into a [Carthage/Checkouts][] folder, then build each one or download a pre-compiled framework. 1. On your application targets’ _General_ settings tab, in the “Linked Frameworks and Libraries” section, drag and drop each framework you want to use from the [Carthage/Build][] folder on disk. 1. On your application targets’ _Build Phases_ settings tab, click the _+_ icon and choose _New Run Script Phase_. Create a Run Script in which you specify your shell (ex: `/bin/sh`), add the following contents to the script area below the shell: ###### Automatic ```sh - /usr/local/bin/carthage copy-frameworks --auto + carthage++ copy-frameworks --auto ``` -From this point Carthage will infer and copy all Carthage's frameworks that are linked against target. It also capable to copy transitive frameworks. For example, you have linked to your app `SocialSDK-Swift` that links internally `SocialSDK-ObjC` which in turns uses utilitary dependency `SocialTools`. In this case you don't need transient dependencies it should be enough to link against your target only `SocialSDK-Swift`. Transient dependencies will be resolved and copied automatically to your app. +From this point Carthage++ will infer and copy all Carthage++'s frameworks that are linked against target. It also capable to copy transitive frameworks. For example, you have linked to your app `SocialSDK-Swift` that links internally `SocialSDK-ObjC` which in turns uses utilitary dependency `SocialTools`. In this case you don't need transient dependencies it should be enough to link against your target only `SocialSDK-Swift`. Transient dependencies will be resolved and copied automatically to your app. Optionally you can add `--verbose` flag to see which frameworks are being copied by Carthage. ###### Manual ```sh - /usr/local/bin/carthage copy-frameworks + carthage++ copy-frameworks ``` 1. Add the paths to the frameworks you want to use under “Input Files". For example: @@ -263,7 +264,7 @@ Optionally you can add `--verbose` flag to see which frameworks are being copied $(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/ReactiveCocoa.framework ``` - With output files specified alongside the input files, Xcode only needs to run the script when the input files have changed or the output files are missing. This means dirty builds will be faster when you haven't rebuilt frameworks with Carthage. + With output files specified alongside the input files, Xcode only needs to run the script when the input files have changed or the output files are missing. This means dirty builds will be faster when you haven't rebuilt frameworks with Carthage++. This script works around an [App Store submission bug](http://www.openradar.me/radar?id=6409498411401216) triggered by universal binaries and ensures that necessary bitcode-related files and dSYMs are copied when archiving. @@ -273,16 +274,16 @@ When archiving your application for submission to the App Store or TestFlight, X ###### Combining Automatic and Manual copying -Note that you can combine both automatic and manual ways to copy frameworks, however manually specified frameworks always take precedence over automatically inferred. Therefore in case you have `SomeFramework.framework` located anywhere as well as `SomeFramework.framework` located at `./Carthage/Build//`, Carthage will pick manually specified framework. This is useful when you're working with development frameworks and want to copy your version of the framework instead of default one. -Important to undestand, that Carthage won't resolve transient dependencies for your custom framework unless they either located at `./Carthage/Build//` or specified manually in “Input Files". +Note that you can combine both automatic and manual ways to copy frameworks, however manually specified frameworks always take precedence over automatically inferred. Therefore in case you have `SomeFramework.framework` located anywhere as well as `SomeFramework.framework` located at `./Carthage/Build//`, Carthage++ will pick manually specified framework. This is useful when you're working with development frameworks and want to copy your version of the framework instead of default one. +Important to undestand, that Carthage++ won't resolve transient dependencies for your custom framework unless they either located at `./Carthage/Build//` or specified manually in “Input Files". ###### Automatic depencencies copying FRAMEWORK_SEARCH_PATHS -If you're working on a development dependencies and would like to utilize `--auto` flag to automate copying of the build artifacts you also can be interested in using `--use-framework-search-paths` flag. This will instruct Carthage to search for a linked dependcies and copy them using `FRAMEWORK_SEARCH_PATHS` environment variable. +If you're working on a development dependencies and would like to utilize `--auto` flag to automate copying of the build artifacts you also can be interested in using `--use-framework-search-paths` flag. This will instruct Carthage++ to search for a linked dependcies and copy them using `FRAMEWORK_SEARCH_PATHS` environment variable. ##### For both platforms -Along the way, Carthage will have created some [build artifacts][Artifacts]. The most important of these is the [Cartfile.resolved][] file, which lists the versions that were actually built for each framework. **Make sure to commit your [Cartfile.resolved][]**, because anyone else using the project will need that file to build the same framework versions. +Along the way, Carthage++ will have created some [build artifacts][Artifacts]. The most important of these is the [Cartfile.resolved][] file, which lists the versions that were actually built for each framework. **Make sure to commit your [Cartfile.resolved][]**, because anyone else using the project will need that file to build the same framework versions. ##### (Optionally) Add build phase to warn about outdated dependencies @@ -291,92 +292,92 @@ You can add a Run Script phase to automatically warn you when one of your depend 1. On your application targets’ `Build Phases` settings tab, click the `+` icon and choose `New Run Script Phase`. Create a Run Script in which you specify your shell (ex: `/bin/sh`), add the following contents to the script area below the shell: ```sh -/usr/local/bin/carthage outdated --xcode-warnings | 2>/dev/null +carthage++ outdated --xcode-warnings | 2>/dev/null ``` ##### Swift binary framework download compatibility -Carthage will check to make sure that downloaded Swift (and mixed Objective-C/Swift) frameworks were built with the same version of Swift that is in use locally. If there is a version mismatch, Carthage will proceed to build the framework from source. If the framework cannot be built from source, Carthage will fail. +Carthage++ will check to make sure that downloaded Swift (and mixed Objective-C/Swift) frameworks were built with the same version of Swift that is in use locally. If there is a version mismatch, Carthage++ will proceed to build the framework from source. If the framework cannot be built from source, Carthage++ will fail. -Because Carthage uses the output of `xcrun swift --version` to determine the local Swift version, make sure to run Carthage commands with the Swift toolchain that you intend to use. For many use cases, nothing additional is needed. However, for example, if you are building a Swift 2.3 project using Xcode 8.x, one approach to specifying your default `swift` for `carthage bootstrap` is to use the following command: +Because Carthage++ uses the output of `xcrun swift --version` to determine the local Swift version, make sure to run the Carthage++ commands with the Swift toolchain that you intend to use. For many use cases, nothing additional is needed. However, for example, if you are building a Swift 2.3 project using Xcode 8.x, one approach to specifying your default `swift` for `carthage++ bootstrap` is to use the following command: ``` -TOOLCHAINS=com.apple.dt.toolchain.Swift_2_3 carthage bootstrap +TOOLCHAINS=com.apple.dt.toolchain.Swift_2_3 carthage++ bootstrap ``` -### Running a project that uses Carthage +### Running a project that uses Carthage++ -After you’ve finished the above steps and pushed your changes, other users of the project only need to fetch the repository and run `carthage bootstrap` to get started with the frameworks you’ve added. +After you’ve finished the above steps and pushed your changes, other users of the project only need to fetch the repository and run `carthage++ bootstrap` to get started with the frameworks you’ve added. ### Adding frameworks to unit tests or a framework -Using Carthage for the dependencies of any arbitrary target is fairly similar to [using Carthage for an application](#adding-frameworks-to-an-application). The main difference lies in how the frameworks are actually set up and linked in Xcode. +Using Carthage++ for the dependencies of any arbitrary target is fairly similar to [using Carthage++ for an application](#adding-frameworks-to-an-application). The main difference lies in how the frameworks are actually set up and linked in Xcode. Because unit test targets are missing the _Linked Frameworks and Libraries_ section in their _General_ settings tab, you must instead drag the [built frameworks][Carthage/Build] to the _Link Binaries With Libraries_ build phase. In the Test target under the _Build Settings_ tab, add `@loader_path/Frameworks` to the _Runpath Search Paths_ if it isn't already present. -In rare cases, you may want to also copy each dependency into the build product (e.g., to embed dependencies within the outer framework, or make sure dependencies are present in a test bundle). To do this, create a new _Copy Files_ build phase with the _Frameworks_ destination, then add the framework reference there as well. You shouldn't use the `carthage copy-frameworks` command since test bundles don't need frameworks stripped, and running concurrent instances of `copy-frameworks` (with parallel builds turn on) is not supported. +In rare cases, you may want to also copy each dependency into the build product (e.g., to embed dependencies within the outer framework, or make sure dependencies are present in a test bundle). To do this, create a new _Copy Files_ build phase with the _Frameworks_ destination, then add the framework reference there as well. You shouldn't use the `carthage++ copy-frameworks` command since test bundles don't need frameworks stripped, and running concurrent instances of `copy-frameworks` (with parallel builds turn on) is not supported. ### Upgrading frameworks -If you’ve modified your [Cartfile][], or you want to update to the newest versions of each framework (subject to the requirements you’ve specified), simply run the `carthage update` command again. +If you’ve modified your [Cartfile][], or you want to update to the newest versions of each framework (subject to the requirements you’ve specified), simply run the `carthage++ update` command again. If you only want to update one, or specific, dependencies, pass them as a space-separated list to the `update` command. e.g. ``` -carthage update Box +carthage++ update Box ``` or ``` -carthage update Box Result +carthage++ update Box Result ``` ### Diagnosing resolver problems -If you have problematic dependency trees for which the resolver gives unexpected results or performs very slowly, please run the carthage diagnose command and zip the produced results directory. This can be used to setup an offline test case for this dependency tree. You can anonimize the names of dependencies used via a mapping file. Please see: +If you have problematic dependency trees for which the resolver gives unexpected results or performs very slowly, please run the `carthage++ diagnose` command and zip the produced results directory. This can be used to setup an offline test case for this dependency tree. You can anonimize the names of dependencies used via a mapping file. Please see: ``` -carthage help diagnose +carthage++ help diagnose ``` ### Nested dependencies -If the framework you want to add to your project has dependencies explicitly listed in a [Cartfile][], Carthage will automatically retrieve them for you. You will then have to **drag them yourself into your project** from the [Carthage/Build] folder. +If the framework you want to add to your project has dependencies explicitly listed in a [Cartfile][], Carthage++ will automatically retrieve them for you. You will then have to **drag them yourself into your project** from the [Carthage/Build] folder. If the embedded framework in your project has dependencies to other frameworks you must **link them to application target** (even if application target does not have dependency to that frameworks and never uses them). ### Using submodules for dependencies -By default, Carthage will directly [check out][Carthage/Checkouts] dependencies’ source files into your project folder, leaving you to commit or ignore them as you choose. If you’d like to have dependencies available as Git submodules instead (perhaps so you can commit and push changes within them), you can run `carthage update` or `carthage checkout` with the `--use-submodules` flag. +By default, Carthage++ will directly [check out][Carthage/Checkouts] dependencies’ source files into your project folder, leaving you to commit or ignore them as you choose. If you’d like to have dependencies available as Git submodules instead (perhaps so you can commit and push changes within them), you can run `carthage++ update` or `carthage++ checkout` with the `--use-submodules` flag. -When run this way, Carthage will write to your repository’s `.gitmodules` and `.git/config` files, and automatically update the submodules when the dependencies’ versions change. +When run this way, Carthage++ will write to your repository’s `.gitmodules` and `.git/config` files, and automatically update the submodules when the dependencies’ versions change. ### Automatically rebuilding dependencies -If you want to work on your dependencies during development, and want them to be automatically rebuilt when you build your parent project, you can add a Run Script build phase that invokes Carthage like so: +If you want to work on your dependencies during development, and want them to be automatically rebuilt when you build your parent project, you can add a Run Script build phase that invokes Carthage++ like so: ```sh -/usr/local/bin/carthage build --platform "$PLATFORM_NAME" --project-directory "$SRCROOT" +carthage++ build --platform "$PLATFORM_NAME" --project-directory "$SRCROOT" ``` Note that you should be [using submodules](#using-submodules-for-dependencies) before doing this, because plain checkouts [should not be modified][Carthage/Checkouts] directly. ### Caching builds -By default Carthage will rebuild a dependency regardless of whether it's the same resolved version as before. Passing the `--cache-builds` will cause carthage to avoid rebuilding a dependency if it can. See information on [version files][VersionFile] for details on how Carthage performs this caching. +By default Carthage++ will rebuild a dependency regardless of whether it's the same resolved version as before. Passing the `--cache-builds` will cause carthage++ to avoid rebuilding a dependency if it can. See information on [version files][VersionFile] for details on how Carthage++ performs this caching. -Note: At this time `--cache-builds` is incompatible with `--use-submodules`. Using both will result in working copy and committed changes to your submodule dependency not being correctly rebuilt. See [#1785](https://github.com/Carthage/Carthage/issues/1785) for details. +Note: At this time `--cache-builds` is incompatible with `--use-submodules`. Using both will result in working copy and committed changes to your submodule dependency not being correctly rebuilt. See [#1785](https://github.com/nsoperations/Carthage/issues/1785) for details. The option `--use-binaries` (which is true by default, specify `--no-use-binaries` to disable) will try to find binary cached dependencies. This works independently of the `--cache-builds` option. Binaries will be resolved from the local shared cache or, if not available there, will be downloaded from a remote location. -By default Carthage will use remote binary caching based on releases published in GitHub. However there is a plugable caching mechanism exposed via the `--cache-command` option which can be supplied to all commands which execute carthage build (update, bootstrap, build). Specify a custom executable with this `--cache-command` option to implement caching in a custom way or specify the environment variable CARTHAGE_CACHE_COMMAND to achieve the same. +By default Carthage++ will use remote binary caching based on releases published in GitHub. However there is a plugable caching mechanism exposed via the `--cache-command` option which can be supplied to all commands which execute carthage++ build (update, bootstrap, build). Specify a custom executable with this `--cache-command` option to implement caching in a custom way or specify the environment variable CARTHAGE_CACHE_COMMAND to achieve the same. The executable will receive five environment variables from Carthage: [CARTHAGE_CACHE_DEPENDENCY_NAME, CARTHAGE_CACHE_DEPENDENCY_VERSION, CARTHAGE_CACHE_BUILD_CONFIGURATION, CARTHAGE_CACHE_SWIFT_VERSION, CARTHAGE_CACHE_TARGET_FILE_PATH] -The executable should resolve a binary zip file as produced via the carthage archive command (or carthage build --archive) compatible with the specified dependency options (name, version, build config, swift toolchain version) and should move the file to the file path denoted by the CARTHAGE_CACHE_TARGET_FILE_PATH environment variable. +The executable should resolve a binary zip file as produced via the `carthage++ archive` command (or `carthage++ build --archive`) compatible with the specified dependency options (name, version, build config, swift toolchain version) and should move the file to the file path denoted by the CARTHAGE_CACHE_TARGET_FILE_PATH environment variable. ### HTTP authentication for binaries @@ -386,58 +387,58 @@ For OAuth2 bearer token authentication: specify `oauth2` as login and the token ### Bash/Zsh/Fish completion -Auto completion of Carthage commands and options are available as documented in [Bash/Zsh/Fish Completion][Bash/Zsh/Fish Completion]. +Auto completion of Carthage++ commands and options are available as documented in [Bash/Zsh/Fish Completion][Bash/Zsh/Fish Completion]. -## Supporting Carthage for your framework +## Supporting Carthage++ for your framework -**Carthage only officially supports dynamic frameworks**. Dynamic frameworks can be used on any version of OS X, but only on **iOS 8 or later**. Additionally, since version 0.30.0 Carhage supports **static** frameworks. +**Carthage++ only officially supports dynamic frameworks**. Dynamic frameworks can be used on any version of OS X, but only on **iOS 8 or later**. Additionally, since version 0.30.0 Carhage supports **static** frameworks. -Because Carthage has no centralized package list, and no project specification format, **most frameworks should build automatically**. +Because Carthage++ has no centralized package list, and no project specification format, **most frameworks should build automatically**. The specific requirements of any framework project are listed below. ### Share your Xcode schemes -Carthage will only build Xcode schemes that are shared from your `.xcodeproj`. You can see if all of your intended schemes build successfully by running `carthage build --no-skip-current`, then checking the [Carthage/Build][] folder. +Carthage++ will only build Xcode schemes that are shared from your `.xcodeproj`. You can see if all of your intended schemes build successfully by running `carthage++ build --no-skip-current`, then checking the [Carthage/Build][] folder. -If an important scheme is not built when you run that command, open Xcode and make sure that the [scheme is marked as _Shared_](https://developer.apple.com/library/content/documentation/IDEs/Conceptual/xcode_guide-continuous_integration/ConfigureBots.html#//apple_ref/doc/uid/TP40013292-CH9-SW3), so Carthage can discover it. +If an important scheme is not built when you run that command, open Xcode and make sure that the [scheme is marked as _Shared_](https://developer.apple.com/library/content/documentation/IDEs/Conceptual/xcode_guide-continuous_integration/ConfigureBots.html#//apple_ref/doc/uid/TP40013292-CH9-SW3), so Carthage++ can discover it. ### Filter discoverable schemes -To only expose a subset of the shared schemes to Carthage add a Cartfile.schemes to your project listing the scheme names to consider. List one scheme name per line. Schemes not listed in this file will be ignored. +To only expose a subset of the shared schemes to Carthage++ add a Cartfile.schemes to your project listing the scheme names to consider. List one scheme name per line. Schemes not listed in this file will be ignored. ### Resolve build failures -If you encounter build failures in `carthage build --no-skip-current`, try running `xcodebuild -scheme SCHEME -workspace WORKSPACE build` or `xcodebuild -scheme SCHEME -project PROJECT build` (with the actual values) and see if the same failure occurs there. This should hopefully yield enough information to resolve the problem. +If you encounter build failures in `carthage++ build --no-skip-current`, try running `xcodebuild -scheme SCHEME -workspace WORKSPACE build` or `xcodebuild -scheme SCHEME -project PROJECT build` (with the actual values) and see if the same failure occurs there. This should hopefully yield enough information to resolve the problem. -If you have multiple versions of the Apple developer tools installed (an Xcode beta, for example), use `xcode-select` to change which version Carthage uses. +If you have multiple versions of the Apple developer tools installed (an Xcode beta, for example), use `xcode-select` to change which version Carthage++ uses. -If you’re still not able to build your framework with Carthage, please [open an issue](https://github.com/Carthage/Carthage/issues/new) and we’d be happy to help! +If you’re still not able to build your framework with Carthage++, please [open an issue](https://github.com/nsoperations/Carthage/issues/new) and we’d be happy to help! ### Tag stable releases -Carthage determines which versions of your framework are available by searching through the tags published on the repository, and trying to interpret each tag name as a [semantic version](https://semver.org/). For example, in the tag `v1.2`, the semantic version is 1.2.0. +Carthage++ determines which versions of your framework are available by searching through the tags published on the repository, and trying to interpret each tag name as a [semantic version](https://semver.org/). For example, in the tag `v1.2`, the semantic version is 1.2.0. Tags without any version number, or with any characters following the version number (e.g., `1.2-alpha-1`) are currently unsupported, and will be ignored. ### Archive prebuilt frameworks into one zip file -Carthage can automatically use prebuilt frameworks, instead of building from scratch, if they are attached to a [GitHub Release](https://help.github.com/articles/about-releases/) on your project’s repository or via a binary project definition file. +Carthage++ can automatically use prebuilt frameworks, instead of building from scratch, if they are attached to a [GitHub Release](https://help.github.com/articles/about-releases/) on your project’s repository or via a binary project definition file. -To offer prebuilt frameworks for a specific tag, the binaries for _all_ supported platforms should be zipped up together into _one_ archive, and that archive should be attached to a published Release corresponding to that tag. The attachment should include `.framework` in its name (e.g., `ReactiveCocoa.framework.zip`), to indicate to Carthage that it contains binaries. The directory structure of the acthive is free form but, __frameworks should only appear once in the archive__ as they will be copied +To offer prebuilt frameworks for a specific tag, the binaries for _all_ supported platforms should be zipped up together into _one_ archive, and that archive should be attached to a published Release corresponding to that tag. The attachment should include `.framework` in its name (e.g., `ReactiveCocoa.framework.zip`), to indicate to Carthage++ that it contains binaries. The directory structure of the acthive is free form but, __frameworks should only appear once in the archive__ as they will be copied to `Carthage/Build/` based on their name (e.g. `ReactiveCocoa.framework`). -You can perform the archiving operation with carthage itself using: +You can perform the archiving operation with carthage++ itself using: ```sh --carthage build --no-skip-current --carthage archive YourFrameworkName +-carthage++ build --no-skip-current +-carthage++ archive YourFrameworkName ``` or alternatively ```sh -carthage build --archive +carthage++ build --archive ``` Draft Releases will be automatically ignored, even if they correspond to the desired tag. @@ -474,14 +475,14 @@ It is possible to use travis-ci in order to build and upload your tagged release - FRAMEWORK_NAME= before_install: - brew update - - brew outdated carthage || brew upgrade carthage + - brew outdated carthage++ || brew upgrade carthage++ before_script: # bootstrap the dependencies for the project # you can remove if you don't have dependencies - - carthage bootstrap + - carthage++ bootstrap before_deploy: - - carthage build --no-skip-current - - carthage archive $FRAMEWORK_NAME + - carthage++ build --no-skip-current + - carthage++ archive $FRAMEWORK_NAME ``` 1. Run `travis setup releases`, follow documentation [here](https://docs.travis-ci.com/user/deployment/releases/) @@ -510,67 +511,67 @@ It is possible to use travis-ci in order to build and upload your tagged release ### Build static frameworks to speed up your app’s launch times -If you embed many dynamic frameworks into your app, its pre-main launch times may be quite slow. Carthage is able to help mitigate this by building your dynamic frameworks as static frameworks instead. Static frameworks can be linked directly into your application or merged together into a larger dynamic framework with a few simple modifications to your workflow, which can result in dramatic reductions in pre-main launch times. +If you embed many dynamic frameworks into your app, its pre-main launch times may be quite slow. Carthage++ is able to help mitigate this by building your dynamic frameworks as static frameworks instead. Static frameworks can be linked directly into your application or merged together into a larger dynamic framework with a few simple modifications to your workflow, which can result in dramatic reductions in pre-main launch times. -#### Carthage 0.30.0 or higher +#### Carthage++ 0.30.0 or higher -Since version 0.30.0 Carthage project rolls out support for statically linked frameworks written in Swift or Objective-C, support for which has been introduced in Xcode 9.4. Please note however that it specifically says *frameworks*, hence Darwin bundles with **.framework** extension and statically linked object archives inside. Carthage does not currently support static *library* schemes, nor are there any plans to introduce their support in the future. +Since version 0.30.0 Carthage++ project rolls out support for statically linked frameworks written in Swift or Objective-C, support for which has been introduced in Xcode 9.4. Please note however that it specifically says *frameworks*, hence Darwin bundles with **.framework** extension and statically linked object archives inside. Carthage++ does not currently support static *library* schemes, nor are there any plans to introduce their support in the future. The workflow differs barely: -- You still need to tick your Carthage-compliant project's schemes as *shared* in *Product > Scheme > Manage Schemes...*, just as with dynamic binaries +- You still need to tick your Carthage++-compliant project's schemes as *shared* in *Product > Scheme > Manage Schemes...*, just as with dynamic binaries - You still need to link against static **.frameworks** in your project's *Build Phases* just as with dynamic binaries However: - In your Carthage-compliant project's Cocoa Framework target's *Build Settings*, *Linking* section, set **Mach-O Type** to **Static Library** - Your statically linked frameworks will be built at *./Carthage/Build/$(PLATFORM_NAME)/Static* -- You should not add any of static frameworks as input/output files in **carthage copy-frameworks** *Build Phase* +- You should not add any of static frameworks as input/output files in **carthage++ copy-frameworks** *Build Phase* -#### Carthage 0.29.0 or lower +#### Carthage++ 0.29.0 or lower See the [StaticFrameworks][StaticFrameworks] doc for details. *Please note that a few caveats apply to this approach:* - Swift static frameworks are not officially supported by Apple -- This is an advanced workflow that is not built into Carthage, YMMV +- This is an advanced workflow that is not built into Carthage++, YMMV ### Declare your compatibility -Want to advertise that your project can be used with Carthage? You can add a compatibility badge: +Want to advertise that your project can be used with Carthage/Carthage++? You can add a compatibility badge: -[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) +[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/nsoperations/Carthage) … to your `README`, by simply inserting the following Markdown: ```markdown -[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) +[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/nsoperations/Carthage) ``` ## CarthageKit -Most of the functionality of the `carthage` command line tool is actually encapsulated in a framework named CarthageKit. +Most of the functionality of the `carthage++` command line tool is actually encapsulated in a framework named CarthageKit. -If you’re interested in using Carthage as part of another tool, or perhaps extending the functionality of Carthage, take a look at the [CarthageKit][] source code to see if the API fits your needs. +If you’re interested in using Carthage++ as part of another tool, or perhaps extending the functionality of Carthage, take a look at the [CarthageKit][] source code to see if the API fits your needs. -## Differences between Carthage and CocoaPods +## Differences between Carthage++ and CocoaPods -[CocoaPods](http://cocoapods.org/) is a long-standing dependency manager for Cocoa. So why was Carthage created? +[CocoaPods](http://cocoapods.org/) is a long-standing dependency manager for Cocoa. So why was Carthage++ created? -Firstly, CocoaPods (by default) automatically creates and updates an Xcode workspace for your application and all dependencies. Carthage builds framework binaries using `xcodebuild`, but leaves the responsibility of integrating them up to the user. CocoaPods’ approach is easier to use, while Carthage’s is flexible and unintrusive. +Firstly, CocoaPods (by default) automatically creates and updates an Xcode workspace for your application and all dependencies. Carthage++ builds framework binaries using `xcodebuild`, but leaves the responsibility of integrating them up to the user. CocoaPods’ approach is easier to use, while Carthage++’s is flexible and unintrusive. The goal of CocoaPods is listed in its [README](https://github.com/CocoaPods/CocoaPods/blob/1703a3464674baecf54bd7e766f4b37ed8fc43f7/README.md) as follows: > … to improve discoverability of, and engagement in, third party open-source libraries, by creating a more centralized ecosystem. -By contrast, Carthage has been created as a _decentralized_ dependency manager. There is no central list of projects, which reduces maintenance work and avoids any central point of failure. However, project discovery is more difficult—users must resort to GitHub’s [Trending](https://github.com/trending?l=swift) pages or similar. +By contrast, Carthage++ has been created as a _decentralized_ dependency manager. There is no central list of projects, which reduces maintenance work and avoids any central point of failure. However, project discovery is more difficult—users must resort to GitHub’s [Trending](https://github.com/trending?l=swift) pages or similar. -CocoaPods projects must also have what’s known as a [podspec](http://guides.cocoapods.org/syntax/podspec.html) file, which includes metadata about the project and specifies how it should be built. Carthage uses `xcodebuild` to build dependencies, instead of integrating them into a single workspace, it doesn’t have a similar specification file but your dependencies must include their own Xcode project that describes how to build their products. +CocoaPods projects must also have what’s known as a [podspec](http://guides.cocoapods.org/syntax/podspec.html) file, which includes metadata about the project and specifies how it should be built. Carthage++ uses `xcodebuild` to build dependencies, instead of integrating them into a single workspace, it doesn’t have a similar specification file but your dependencies must include their own Xcode project that describes how to build their products. -Ultimately, we created Carthage because we wanted the simplest tool possible—a dependency manager that gets the job done without taking over the responsibility of Xcode, and without creating extra work for framework authors. CocoaPods offers many amazing features that Carthage will never have, at the expense of additional complexity. +Ultimately, we created Carthage++ because we wanted the simplest tool possible—a dependency manager that gets the job done without taking over the responsibility of Xcode, and without creating extra work for framework authors. CocoaPods offers many amazing features that Carthage++ will never have, at the expense of additional complexity. ## License -Carthage is released under the [MIT License](LICENSE.md). +Carthage++ is released under the [MIT License](LICENSE.md). Header backdrop photo is released under the [CC BY-NC-SA 2.0](https://creativecommons.org/licenses/by-nc-sa/2.0/) license. Original photo by [Richard Mortel](https://www.flickr.com/photos/prof_richard/). diff --git a/Source/CarthageKit/CarthageKitVersion.swift b/Source/CarthageKit/CarthageKitVersion.swift index f346054d..fd63a37d 100644 --- a/Source/CarthageKit/CarthageKitVersion.swift +++ b/Source/CarthageKit/CarthageKitVersion.swift @@ -1,5 +1,5 @@ /// Defines the current CarthageKit version. public struct CarthageKitVersion { public let value: SemanticVersion - public static let current = CarthageKitVersion(value: SemanticVersion(0, 40, 1, prereleaseIdentifiers: [], buildMetadataIdentifiers: ["nsoperations"])) + public static let current = CarthageKitVersion(value: SemanticVersion(0, 40, 2, prereleaseIdentifiers: [], buildMetadataIdentifiers: [])) }