コネヒト開発者ブログ

コネヒト開発者ブログ

Swift製CLIツールをMintを使わずSwiftPMで管理する

こんにちは!エンジニアの柳村です。

SwiftLintやSwiftFormat,XcodeGenといったSwift製のコマンドラインツールを管理するために、同じくSwift製であるMintを使っているのを割とよく見かけます。 Mintは便利ですが、Mint自体をなにかしらの手段でインストールしなければならないという問題がでてきます。

そこでMintは使わずSwift Package ManagerでSwift製のコマンドラインツールを管理する方法をご紹介します。

方法

Package.swiftを用意します。 nameを適当に設定し、dependenciesに利用したいコマンドラインツールのリポジトリのurlと必要であればバージョンを指定します。

// swift-tools-version:5.1
import PackageDescription

let package = Package(
    name: "Tools",
    dependencies: [
        .package(url: "https://github.com/apple/swift-format", .branch("master")),
        .package(url: "https://github.com/yonaskolb/XcodeGen", from: "2.13.0"),
        .package(url: "https://github.com/mac-cain13/R.swift", .exact("5.1.0")),
    ]
)

あとはswift runするだけです。

$ swift run -c release swift-format --help

最初の実行時はコマンドラインツールのビルドが行われるため結構時間がかかりますが、2回目以降は.build/release以下にビルド結果が残っているのでビルドなしで実行できます。

Swift Package Managerでツール以外のパッケージも管理している場合

Swift Package Managerを使っていないプロジェクトの場合は、なにも考えずにプロジェクトのルート直下にPackage.swiftを配置しても特に問題ないと思いますが、既にSwift Package Managerを使ってる場合は対処が必要です。

なぜなら、Swift Package Managerはdebugビルドやtestのときのみのdependenciesを設定する機能がないため、dependenciesに書いたものは必ずダウンロードとビルドが実行されてしまうからです。そのためリリースビルドなどが無駄に遅くなってしまったりします。

対処方法

その1. ディレクトリを分ける

コマンドラインツール系は別のディレクトリにおいてしまうのが手っ取り早い方法です。

例えば、cliというディレクトリをプロジェクト内につくって、そのディレクトリ内にコマンドラインツールのdependenciesを書いたPackage.swiftを配置しswift runを実行すればよいです。swift run --package-path cli xcodegenというふうに--package-pathでPackage.swiftのあるディレクトリを指定すればcliディレクトリに移動せずにswift runすることができます。

その2. 別の名前のPackage.swiftを用意して実行時にPackage.swiftに置き換える

Swift Package Manager製のコマンドラインツールの開発で使われたりするやり方で、例えばPackage.test.swiftというテスト用のファイルを用意しておいて、テストするときだけPackage.test.swiftをPackage.swiftに置き換えます。

普通のiOSアプリ開発の場合は、Package.release.swiftというファイルを用意しておいて、CIなどでリリースビルドするときだけPackage.release.swiftをPackage.swiftに置き換えてやるとよいのではないかと思います。

ただ、2つのファイルをメンテしなければならないといったデメリットがあります。

Mintとの違い

最後にMintとの違いについて触れておきます。

Mintはglobalに保存

Swift Package Managerの場合はPackage.swiftのあるディレクトリの.build以下にcloneやビルド結果が保存されますが、 Mintの場合は/usr/local/lib/mint/以下に保存されます。複数のプロジェクトがあり、他のプロジェクトと同じバージョンのパッケージを使っていた場合はキャッシュが効くメリットがあります。

Mintはglobal linkつくるのが楽

MintはCLIを実行するrunだけでなく、globalにinstallするinstallという機能があります。 どいういうことかというと、例えばmint install yonaskolb/XcodeGenを実行しておくと、/usr/local/bin以下に実行ファイルのリンクがつくられるので、mint run xcodegenとしなくても、xcodegenだけで実行できるようになります。

Mintはconfig fileなしで実行できる

Swift Package Managerの場合Package.swiftを用意しなければなりませんが、Mintの場合はMintfileなしでも使えます。

まとめ

基本的にはMint使わなくてもSwift Package Managerで事足りるのではないかなと思っています。

ただ、SwiftLintの0.38.xはビルド通らないようでした(https://github.com/realm/SwiftLint/issues/2867)のでご注意ください。(0.39.0で治りました)

そしてコネヒトではエンジニアを募集しておりますので少しでも興味のある人はお話だけでも聞きにきてください! www.wantedly.com