こんにちは!エンジニアの柳村です。
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