[iOS]Mintを使ってプロジェクトごとのSwift製CLIツールのパッケージ管理を行う

プロジェクトごとにSwift製のCLIツールを管理するMintを試しました。
2020.11.02

Homebrewを使っていたのですが、Swift製のコマンドラインツールのSwiftLintやSwiftGen、Carthageなどを使う時にプロジェクトごとにこれらのツールのバージョン管理うまいことやりたいと思いました。身近な例だとBundlerがやっていることをSwift製のパッケージ管理でも行いたいです。今回はせっかくなので自分の環境が原因で手間取ったSwiftLintをローカルでMintで入れてみてプロジェクトで使用してみるまでを記事にします。

インストールとセットアップ

リポジトリは以下です。

インストール方法はREADME.md色々あるので手元の環境に合わせてください。今回はcloneしてきてビルドしました。

$ git clone https://github.com/yonaskolb/Mint.git
$ cd Mint
$ swift run mint install yonaskolb/mint

記事執筆時のバージョンは以下です。

$ mint version
Version: 0.14.2

makeでのインストールに11/1時点で失敗する

インストール方法は複数ありますが、makeでイントールしようとするとpathが間違っているというエラーが出てきます。

91%: Copy Mint.swiftsourceinfo (x86_64)
91%: Copy Mint.swiftsourceinfo (x86_64)
91%: Copy Mint.swiftmodule (x86_64)
98%: Generate mint.dSYM
98%: Register execution policy exception for mint
100%: Build succeeded
mkdir -p /usr/local/bin
cp -f .build/release/mint /usr/local/bin/mint
cp: .build/release/mint: No such file or directory
make: *** [install] Error 1

Mint on  master took 45s

これに関してissueも立っていてそれに対してPRも出ていますがマージされるまで他の方法で導入した方が良いかもしれません。

PRは以下

基本的な使い方

helpコマンドがありますので説明が必要そうなものだけ抜粋します。runコマンドはインストールと実行を合わせてやってくれます。listコマンドでインストールしたツールを一覧で見れます

bootstrapコマンドでMintfileに記述したパッケージをグローバルなくローカルにインストールできます。パッケージのインストールに失敗することもあると思うのでその時は—verboseオプションを付与するのが良さそうです。

mint help

Usage: mint <command> [options]

Run and install Swift Package Manager executables

Commands:
  run             Install and then run a package
  install         Install a package. If the version is already installed no action will be taken
  uninstall       Uninstall a package by name
  list            List all the currently installed packages. Globally linked packages are marked with *
  bootstrap       Installs all the packages in a Mintfile
  which           Prints the full path to the installed executable
  help            Prints help information
  version         Prints the current version of this app

以下のようなコマンドでツールをインストールします。アンインストール時も形式は同じです。

mint install パッケージ名(name/repo)@バージョン

任意のバージョンの実行はrunコマンドを使用します。

mint run name/repo@0version repo_name

swift 5.3の環境でSwiftLintのinstallに失敗する

MintのリポジトリのREADME.mdの冒頭に記載してあるSwiftLIntを導入してみます.

mint install realm/SwiftLint@0.40.3

しかし、自分の環境起因でインストールに何度かこけました。swiftlintの.swift_versionに指定されているバージョンと異なるのでインストールに失敗しました。swiftenvでswiftのバージョンを更新します。

🌱 Finding latest version of SwiftLint
🌱 Cloning SwiftLint 0.40.3
🌱 Resolving package
swiftenv: version `5.1' (set by /private/var/folders/d6/wdqrmkd53j728wfxk_xs1snr0000gq/T/mint/github.com_realm_SwiftLint/.swift-version) is not installed
🌱 Encountered error during "swift package resolve". Use --verbose to see full output
🌱  Failed to resolve SwiftLint 0.40.3 with SPM

エラー出力が変わりました。

mint run realm/SwiftLint@0.40.3
🌱 Cloning SwiftLint 0.40.3
🌱 Resolving package
🌱 Building package
[1/12] Compiling SourceKit SourceKit.m
[2/12] Compiling Clang_C Clang_C.m
[3/12] Compiling writer.c
[4/12] Compiling reader.c
[5/12] Compiling parser.c
[6/12] Compiling api.c
[7/12] Compiling emitter.c
[8/12] Compiling scanner.c
[9/13] Compiling SwiftyTextTable TextTable.swift
[10/13] Compiling Commandant Argument.swift
[11/13] Compiling Yams Constructor.swift
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/System/Library/Frameworks/Combine.framework/Modules/Combine.swiftmodule/x86_64-apple-macos.swiftinterface:648:1: error: unknown attribute '_hasMissingDesignatedInitializers'
@_hasMissingDesignatedInitializers @available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
^
/private/var/folders/d6/wdqrmkd53j728wfxk_xs1snr0000gq/T/mint/github.com_realm_SwiftLint/.build/checkouts/Yams/Sources/Yams/Decoder.swift:349:5: error: failed to load module 'Combine'
#if canImport(Combine)
    ^
🌱 Encountered error during "swift build -c release -Xswiftc -target -Xswiftc x86_64-apple-macosx10.15". Use --verbose to see full output
mint install realm/SwiftLint@0.40.3

しかし、自分の環境起因でインストールに失敗しました。

一度目はswiftlintの.swift_versionに指定されているバージョンが見つからないのでインストールに失敗しました。swiftenvで指定のバージョンをインストールします。.swift-versionファイルがローカルでのswiftのバージョンを指定してくれるのでglobalのバージョンは変更する必要がないです。

$swiftenv install 5.1

インストール後にもう一度同じコマンドを実行します。

🌱 Finding latest version of SwiftLint
🌱 Cloning SwiftLint 0.40.3
🌱 Resolving package
swiftenv: version `5.1' (set by /private/var/folders/d6/wdqrmkd53j728wfxk_xs1snr0000gq/T/mint/github.com_realm_SwiftLint/.swift-version) is not installed
🌱 Encountered error during "swift package resolve". Use --verbose to see full output
🌱  Failed to resolve SwiftLint 0.40.3 with SPM
$ sudo xcode-select -s /Applications/Xcode_11.3.1.app/.app/Contents/Developer
$ xcode-select --print-path
/Applications/Xcode_11.3.1.app/Contents/Developer

もう一度インストールを試すと今度は成功しました。

mint install realm/SwiftLint@0.40.3
🌱 Cloning SwiftLint 0.40.3
🌱 Resolving package
🌱 Building package
🌱 Installed SwiftLint 0.40.3
🌱 Linked swiftlint 0.40.3 to /usr/local/bin

mintを通してSwiftLintをインストールした状態で、Build PhasesのRun Scriptを以下のようにします。このあたりのシェルスクリプトはプロジェクトごとに違うと思いますが新規プロジェクトだと以下で動くと思います。

# Type a script or drag a script file from your workspace to insert its path.
if which mint >/dev/null; then
  mint run swiftlint swiftlint autocorrect --format
  mint run swiftlint swiftlint
else
  echo 'warning: Mint not installed. Please install mint from https://github.com/yonaskolb/Mint'
fi

Mintfileを利用したローカルへのインストール

グローバルにインストールしてバージョンを指定することでプロジェクトで利用も出来ますがMintfileを使って利用しているパッケージを一覧できるのもメリットがあると思いますのでやってみます。

Mintfileがないのでmint bootstrapは以下のように失敗します。

mint bootstrap
🌱  Mintfile not found

Mintfile を作成してSwiftLintを指定します。

realm/SwiftLint@0.40.3

インストールに成功しました。

❯ mint bootstrap
🌱 Cloning SwiftLint 0.40.3
🌱 Resolving package
🌱 Building package
🌱 Installed SwiftLint 0.40.3
🌱 Installed 1/1 package

Build Phasesでmintを利用する時、Mintfileでパッケージを指定している場合はMintfileのあるディレクトリでmintコマンドを実行するようにします。

mint runでツールがインストールされていない場合はインストールも行ってくれますが、macOS向けにビルドしているため、Run Scriptを実行中環境変数SDKROOTにセットされているiOSシミュレータ用のSDKだとエラーが発生する場合がります。その場合はスクリプト実行中のみunsetします。

unset SDKROOT

関連するIssueは以下です。

まとめ

Mintのバージョンも1.0になっておらず、README.mdにもUntil 1.0 is reached, minor versions will be breaking.と記載があるように問題が起きるかもしれません。それでも開発は活発なのと、必要ならコントリビュートすれば良いと思うので開発の面倒事を解決できそうなツールは意識して導入していきたいと思います。

Mintをプロジェクトで使いだして間もないので使い慣れてる人からするとこれはどうなんだという説明もあるかもしれません。その際は記事のコメントかTwitterにてご連絡いただければと思います。

記事執筆の際に参考にした記事