CarthageRemoteCache

Test Status Gem Version

Centralized cache to serve Carthage frameworks. Useful for distributed CI setup with several build machines. It's aware of your xcodebuild and swift versions and builds on top of Carthage's .xyz.version file mechanism.

Installation

The gem is published at rubygems.org, installation is as easy as:

$ gem install carthage_remote_cache

Note: Installing ri documentation for sinatra can be quite slow. Install with --no-rdoc --no-ri if you don't want to wait.

Quickstart

  1. Run carthagerc server to start the cache on a remote server
  2. cd to your project's root folder
  3. Run carthagerc init to create Cartrcfile and point the server property to your running server URL
  4. Assuming your Carthage directory is already built, run carthagerc upload to populate remote cache
  5. Push your Cartrcfile and from a different machine run cartrcfile download to fetch frameworks into Carthage/Build/ folder
  6. Build your app without having to wait for carthage bootstrap

Usage

Init

Before running any other commands, it's required to initialize carthagerc in your project directory by running:

$ carthagerc init

Which produces a Cartrcfile. Configuration is done via plain ruby code, so it is as simple as:

Configuration.setup do |c|
  c.server = "http://localhost:9292/"
end

Cartrcfile is supposed to be version controlled (e.g. included in git repository), so that it lives along your code and all consumers of the repository have access to same configuration.

Upload Workflow

Make sure that all your framework binaries have been built with carthage, otherwise there is nothing to upload.

$ carthage bootstrap

Start the upload with:

$ carthagerc upload

After couple of seconds you should be able to see confirmation in terminal:

Uploaded 53 archives (97.2 MB), skipped 0.

Overwriting Existing Cache

Attempting to run carthagerc upload again will not upload any framework binaries, since all of them are already present on the cache server:

Uploaded 0 archives (0.0 MB), skipped 53.

If your cache happens to be tainted by invalid framework binaries, you can overwrite existing cache with

$ carthagerc upload --force

Upgrading Xcode or Swift

It is recommended to always perform the upload workflow after upgrading Xcode and Swift versions since carthagerc cached frameworks are not only bound to framework versions, but also to your build environment.

Download Workflow

Once the cache server has been populated with framework binaries, it's time to fetch frameworks from a different machine. Make sure to pull in Cartrcfile from the repository before executing:

$ carthagerc download

You should expect to see the following output on a machine with empty Carthage folder:

Downloaded and extracted 53 archives (97.2 MB), skipped 0 archives.

Your project should be ready for building.

Overwrite Local Carthage Folder

In case you happen to change a file in Carthage/Build by accident, it's possible to force download all frameworks again with:

$ carthagerc download --force

Download Only Some Platforms

The example above downloaded all frameworks for all platforms (iOS, macOS, tvOS, watchOS). If large dependencies or network speed are an issue, you can download only a subset of the platforms by using the --platform argument:

$ carthagerc download --platform iOS,macOS,tvOS,watchOS

Please note, that invoking the download command multiple times with different platform arguments is not supported. The .version file will "forget" that carthagerc already downloaded the platform specified before the last download. If you need multiple platforms, specify them in a single download command once, delimited with a comma.

Config

To get a quick overview on Xcode / Swift / Framework versions, execute

$ carthagerc config

Which will print similar information:

Xcodebuild: 9C40b
---
Swift: 4.0.3
---
Server: http://localhost:9292/
---
Cartfile.resolved:
github "kayak/attributions" "0.3"
---
Local Build Frameworks:
Attributions 0.3 [:iOS]

Verify Framework Versions

When switching between development branches, it's very easy to lose track of whether existing framework binaries in Carthage/Build match version numbers from Cartfile.resolved. As a result, you will probably lose several minutes of your development time, because Xcode doesn't tell you about outdated or missing framework binaries.

Luckily, carthage_remote_cache provides following command:

carthagerc verify

If existing frameworks match Cartfile.resolved, script exits with 0 and doesn't print anything.

In the event of framework version mismatch, you'll be able to observe following output:

Detected differences between existing frameworks in 'Carthage/Build' and entries in 'Cartfile.resolved':

+-----------------+----------------+-------------------+
| Framework       | Carthage/Build | Cartfile.resolved |
+-----------------+----------------+-------------------+
| CocoaLumberjack |          3.2.1 |             3.4.1 |
| PhoneNumberKit  |          1.3.0 |             2.1.0 |
| HelloWorld      |              - |             3.0.0 |
+-----------------+----------------+-------------------+

To resolve the issue:
- run `carthagerc download` to fetch missing frameworks from the server.
- if the issue persists, run `carthage bootstrap` to build frameworks and `carthagerc upload` to populate the server.

Git Hook

Running carthagerc verify manually on every git checkout / merge / pull could be quite cumbersome. To automate this task, integrate following script carthagerc-verify-githook into your repository's git hooks, e.g. post-checkout.

See $ man githooks for all available git hooks and their documentation.

Cache Server

Start the server with

$ carthagerc server

and browse to localhost:9292 where you should be able to see the default Welcome message.

Framework binaries will be stored in ~/.carthagerc_server folder.

Server is bound to port 9292 by default. If you need to use different port, specify the port number via -pPORT or --port=PORT command line arguments, e.g.:

$ carthage server -p9000
$ carthage server --port=9000

Don't forget to change port number in your version controlled Cartrcfile.

Version Compatibility

Before each carthagerc [upload|download], the script compares its version number against cache server. If the version doesn't match, carthagerc aborts with:

Version mismatch:
  Cache server version: 0.0.7
  Client version:       0.0.6

Please use the same version as cache server is using by running:
$ gem install carthage_remote_cache -v 0.0.7

Please note, that this functionality only works with clients starting with version 0.0.6.

Directory Structure

Cache server stores version files and framework archives in following directory structure:

.carthagerc_server/
  9C40b/                            # Xcode version
    4.0.3/                          # Swift version
      Framework1/
        1.0.0/                      # Framework1 version
          .Framework1.version       # Carthage .version file
          Framework1-iOS.zip        # Framework binary, dSYM and bcsymbolmap files
          Framework1-macOS.zip
          Framework1-tvOS.zip
          Framework1-watchOS.zip
        2.0.3/                      # Framework1 version
          .Framework1.version
          Framework1-iOS.zip
      Framework2/
        v3.2/                       # Framework2 version
          .Framework2.version
          Framework2-iOS.zip

It's safe to delete whole directories since no other metadata is stored.

Launch Agent

You can also run the cache server as a launch agent. Copy the template com.kayak.carthagerc.server.plist file to ~/Library/LaunchAgents, change log paths to include your username and run:

$ launchctl load -w ~/Library/LaunchAgents/com.kayak.carthagerc.server.plist

If you want to stop the agent, run:

$ launchctl unload ~/Library/LaunchAgents/com.kayak.carthagerc.server.plist

Check out official documentation on Launch Agents for more info.

Docker

To build an image based on the latest released gem, run

$ docker build -t carthagerc .

Afterwards you can run the image in a container using

$ docker run -d --publish 9292:9292 --name carthagerc carthagerc:latest

The server will now be available on port 9292 on localhost. Note that the command above will cause any data added to ~/.carthagerc_server to be written into the container layer. While this works, it's generally discouraged due to decreased performance and portability. To avoid this, you can use a volume.

$ docker run -d --publish 9292:9292 --mount "source=carthagerc,target=/root/.carthagerc_server" --name carthagerc carthagerc:latest

We also recommend adding the --log-opt option to limit the size of logs, e.g. --log-opt max-size=50m.

To inspect the logs after running, use

$ docker logs carthagerc

To stop the container, run

$ docker container stop carthagerc

Version

$ carthagerc version

Help

Documentation is also available when running carthagerc or carthagerc --help. Both commands print list of available commands with brief description.

carthagerc COMMAND [OPTIONS]

...

COMMANDS
    config
        print environment information and Cartrcfile configuration

    download [-f|--force] [-v|--verbose] [-mPLATFORM|--platform=PLATFORM]
        fetch missing frameworks into Carthage/Build

    init
        create initial Cartrcfile in current directory

    upload [-f|--force] [-v|--verbose]
        archive frameworks in Carthage/Build and upload them to the server

    server [-pPORT|--port=PORT]
        start cache server

    verify
        compare versions from Cartfile.resolved to existing frameworks in Carthage/Build

    version
        print current version number

OPTIONS
    -f, --force                      Force upload/download of framework archives even if local and server .version files match
    -h, --help                       Show help
    -m, --platform=PLATFORM          Comma delimited list of platforms which should be downloaded from the server; e.g. `--platform iOS,macOS`; Supported values: iOS, macOS, tvOS, watchOS
    -n, --no-retry                   Don't retry download or upload on network failures
    -p, --port=PORT                  Server application port used when starting server, default port is 9292
    -v, --verbose                    Show extra runtime information

Development

Setup

After checking out the repo, run dev/setup to install dependencies. You can also run dev/console for an interactive prompt that will allow you to experiment.

Development Server

To start development server, run dev/start_server, which utilizes rerun for automatic reloading of source code and resources.

Tests

Execute unit tests with rake test or start monitoring directories for changes with bundle exec guard.

Source Code Format

Before committing, make sure to auto-format source code wit rake format.

Gem Lifecycle

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Experiments With Example Folder

Repository is bundled with an example Carthage setup for your experiments. Open the example folder, where you should be able to see following files, which are preconfigured to bring in a couple of frameworks:

  • Cartfile
  • Cartfile.resolved
  • Cartrcfile

Make sure to build these dependencies with carthage bootstrap before attempting to upload them.

Try out a few commands:

$ carthagerc config
$ carthagerc upload
$ carthagerc download

License

The gem is available as open source under the terms of the Apache 2.0 License.