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]
そしてツールの完成形はこちら
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.swift
に Commander
を追加
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です。✨