LoginSignup
4
2

More than 3 years have passed since last update.

Swift Package Managerで簡単なコマンドラインツールを作って試す

Posted at

Swift Package Manager

公式ページ

環境

$ swift package --version
Swift Package Manager - Swift 5.2.0

今回は新たにコマンドラインツールを作る想定で環境を作っていきたいと思います。

$ mkdir spm-sample
$ cd spm-sample
$ swift package init --type=executable
Creating executable package: spm-sample
Creating Package.swift
Creating README.md
Creating .gitignore
Creating Sources/
Creating Sources/spm-sample/main.swift
Creating Tests/
Creating Tests/LinuxMain.swift
Creating Tests/spm-sampleTests/
Creating Tests/spm-sampleTests/spm_sampleTests.swift
Creating Tests/spm-sampleTests/XCTestManifests.swift

--type に関しては以下の種類があります。
- empty
- library
- system-module
- executable
- manifest

一旦ビルドして実行してみます。

$ swift build
$ ./.build/debug/spm-sample
Hello, world!

ちょっとしたツールの作成

作るもの

折角なので、iOS開発を行っていたらいつの間にか色んなファイルで
容量を食ってしまうものを一斉に削除するツールを作ってみたいと思います。
プロジェクト名は iCleaner として作成します。

必要なパッケージを導入

↓のパスを簡単に扱えるようにする PathKit を導入したいと思います。

Package.swift に以下を追加

import PackageDescription

let package = Package(
    name: "iCleaner",
    dependencies: [
        .package(url: "https://github.com/kylef/PathKit.git", from: "1.0.0") // ☆追加
    ],
    targets: [
        .target(
            name: "iCleaner",
            dependencies: ["PathKit"]), // ☆追加
        .testTarget(
            name: "iCleanerTests",
            dependencies: ["iCleaner"]),
    ]
)

試しに以下を main.swift に書いて実行してみます。

import Foundation
import PathKit

let path = FileManager.default.currentDirectoryPath
let currentPath = Path(path)
print(currentPath.glob("*.swift"))
$ swift run
[XXX/iCleaner/Package.swift]

:thumbsup:

そしてツールの完成形はこちら

Cleaner.swift
import Foundation
import PathKit

class Cleaner {
  static let DEVICE_SUPPORT_PATH = "Library/Developer/Xcode/iOS DeviceSupport"
  static let DEVICE_LOGS_PATH = "Library/Developer/Xcode/iOS Device Logs"
  static let ARCHIVES_PATH = "Library/Developer/Xcode/Archives"
  static let DERIVEDDATA_PATH = "Library/Developer/Xcode/DerivedData"

  let homePath: Path
  init() {
    let path = NSHomeDirectory()
    homePath = Path(path)
    print("HOME: \(homePath)")
  }

  func run() {
    // Device support
    let deviceSupportPath = homePath + Path(Cleaner.DEVICE_SUPPORT_PATH)
    if deviceSupportPath.exists {
      deviceSupportPath.glob("*").forEach { try? $0.delete() }
    }

    // Device logs
    let devicelogsPath = homePath + Path(Cleaner.DEVICE_LOGS_PATH)
    if devicelogsPath.exists {
      devicelogsPath.glob("*.db").forEach { try? $0.delete() }
      devicelogsPath.glob("*.db-shm").forEach { try? $0.delete() }
      devicelogsPath.glob("*.db-wal").forEach { try? $0.delete() }
    }

    // Archives
    let archivesPath = homePath + Path(Cleaner.ARCHIVES_PATH)
    if archivesPath.exists {
      archivesPath.glob("*").forEach { try? $0.delete() }
    }

    // DerivedData
    let derivedDataPath = homePath + Path(Cleaner.DERIVEDDATA_PATH)
    if derivedDataPath.exists {
      derivedDataPath.glob("*").forEach { try? $0.delete() }
    }
  }
}
main.swift
let cleaner = Cleaner()
cleaner.run()

swift run で実行する事ができます。

オプションを指定できるようにする

Device Support に関しては使用中のものもあると思うので試しにオプションでスキップできるように
してみたいと思います。

PathKitと同じ作者の Commander を使用します。

Package.swiftCommander を追加

let package = Package(
    name: "iCleaner",
    dependencies: [
        .package(url: "https://github.com/kylef/PathKit.git", from: "1.0.0"),
        .package(url: "https://github.com/kylef/Commander.git", from: "0.9.1") // 追加
    ],
    targets: [
        .target(
            name: "iCleaner",
            dependencies: ["PathKit", "Commander"]), // Commander追加
        .testTarget(
            name: "iCleanerTests",
            dependencies: ["iCleaner"]),
    ]
)

main.swift をオプションが受け付けれるように修正

main.swift
import Commander

command(
  Option("skipds", default: 1, description: "Skip delete Device Support file's.(0: no skip/1: skip)")
) { skipds in
  let cleaner = Cleaner()
  cleaner.run(skipDeviceSupport: skipds == 1)
}.run()

Cleaner クラスにスキップフラグを追加

  func run(skipDeviceSupport: Bool) {
    if !skipDeviceSupport {
      // Device support
      let deviceSupportPath = homePath + Path(Cleaner.DEVICE_SUPPORT_PATH)
      if deviceSupportPath.exists {
        deviceSupportPath.glob("*").forEach { try? $0.delete() }
      }
    }
    ...
  }

リリースビルドして確認してみます。

$ swift build -c release
$ ./.build/release/iCleaner --help 
Usage:

    $ ./.build/release/iCleaner

Options:
    --skipds [default: 1] - Skip delete Device Support file's.(0: no skip/1: skip)

$ ./.build/release/iCleaner --skipds 0
#=> スキップされずに実行

うまくスキップのON/OFFが切り替えれたらOKです。✨

参考にさせて頂いたURL

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2