🍁

Swift Package Manager で Command Line Tool を作る

2021/04/21に公開
1
  1. GitHub でリポジトリを新規に作って、ローカルにcloneする

  2. cloneしたリポジトリのルートディレクトリで SPM の初期化をする

    $ swift package init --type executable
    
  3. Package.swiftを編集する

    Package.swiftの例
    // swift-tools-version:5.5
    
    import PackageDescription
    
    let package = Package(
        name: "LineCounter",
        platforms: [
            .macOS(.v10_15)
        ],
        products: [
            .executable(name: "lc", // コマンド名はここで決められる
                        targets: ["LineCounter"])
        ],
        targets: [
            .target(name: "LineCounter"),
            .testTarget(name: "LineCounterTests",
                        dependencies: ["LineCounter"])
        ]
    )
    
  4. Command Line Tool を実装する

    main.swift
    import Foundation
    
    guard CommandLine.arguments.count == 2 else {
        print("usage: lc [absolute path of a file]")
        exit(1)
    }
    
    let fileUrl = URL(fileURLWithPath: CommandLine.arguments[1])
    guard let file = try? String(contentsOf: fileUrl, encoding: .utf8) else {
        print("Error: could not read \(fileUrl.absoluteString)")
        exit(2)
    }
    
    print(file.components(separatedBy: CharacterSet.newlines).count)
    
  5. ローカルで動作確認をする

    $ swift run lc ${PWD}/Package.swift
    20
    
  6. リモートリポジトリに push して tag を打つ

    tagを打つ
    $ git tag 0.0.1
    $ git push origin 0.0.1
    
    • tag で Command Line Tool のバージョン管理をすることになる
    • GitHub の Release で Change Log をしっかり書くと良い

プロジェクトに作った Command Line Tool を追加してビルド時に実行する

  1. 任意のプロジェクトでFile -> Swift Packages -> Add Package Dependency...を開く

  2. 作った Command Line Tool のリポジトリ URL で検索して Swift Package を追加する

    • この時、Target の中で Command Line Tool を使うわけではないので Target には追加しないようにする
  3. TARGETS -> Build PhasesRun Scriptを追加する

    # build lc
    xcrun --sdk macosx swift build -c release \
    --package-path ${BUILD_DIR%Build/*}SourcePackages/checkouts/LineCounter \
    --product lc
    
    # run lc
    ${BUILD_DIR%Build/*}SourcePackages/checkouts/SwiftLint/.build/release/lc ${SRCROOT}/[目的のファイルのパス]
    
    • swift buildだと実行できないため、xcrun --sdk maxosx swift buildを利用する
    • --package-pathでツールのパスを指定する
    • 相対パスよりも絶対パスを使い、Xcode の環境変数を上手く使う

    これで、Target をビルドするたびにコマンドが実行される

備考: Terminal でコマンドが使えるようにする

リポジトリを任意の場所に git clone して、リリースビルドし、成果物を/usr/local/bin/の中に入れればいい

$ git clone https://github.com/Owner/LineCounter.git
$ swift build -c release
$ cp .build/release/lc /usr/local/bin/lc