游諭 Swift Dev 🦄

使用 Swift Package Manager 建立 Command line tool

Command line tool 有時候可以方便的處理一些常見的任務,有時候可以將開放中遇到的瑣碎事情自動化處理,例如 XcodeGen就是一個有趣的應用。這篇文章將教你如何使用 Swift Package Manager(SPM) 與 Linux/Unix 互動。

先備知識

  1. 基礎 Swift 語法知識,若以 Swift.org 的Language guide 目錄為標準,則是 The BasicMethods
  2. 基礎 Swift Package.init 參數使用,如 name, dependencies, targets
  3. 基礎 Linux 語法知識,如 ls -alR, Date, whoami

建立可執行的SPM - Hello world

我們可以使用 Swift package manager 來建立一個新的 Package project。 如果你對 terminal 熟悉的話,可以閱讀更詳細的文件: Swift-package-manager/Usage.md

$ swift package init --type executable --name helloworld

這段指令執行了一下事情: 在當前目錄建立一個名為 helloworld 的 可執行的Swift package。

你可以看到當前目錄建立了一些檔案,下面是使用 tree 的檔案夾結構:

.
├── Package.swift
├── README.md
├── Sources/
│   └── helloworld/
│       └── main.swift
└── Tests/
    ├── LinuxMain.swift
    └── helloworldTests/
        ├── XCTestManifests.swift
        └── helloworldTests.swift

這時我們可以透過以下指令直接執行這個程式

$ swift build
$ swift run
Hello, world!

如此一來就完成基礎的 Command line tool 了!

Package.swift 取代了 .xcodeproj

若是你有 Xcode 11, 可以直接打開 Package.swift 就會自動 link 所有檔案並建立 .swiftpm

$ open Package.swift

可以看到 Package.swift 成為在 XCode 的第一個檔案,以往熟悉的 .xcodeproj不見了。

在執行檔使用第三方函式庫

在這裏我們為 helloworld 增加讀取 arguments 的功能,我們可以使用其他已經完善的第三方函式庫,這次我們使用 SPMUtility, 這是來自 Apple 的開源專案,SPM 可以透過 Git 目錄的讀取,執行套件管理並安裝到專案中。我們在 Package.swift 中套用以下的修改:

// swift-tools-version:5.1

import PackageDescription

let package = Package(
	name: "helloworld",
	dependencies: [
		.package(url: "https://github.com/apple/swift-package-manager.git", from: "0.1.0")
	],
	targets: [
		.target(
			name: "helloworld",
			dependencies: ["SPMUtility"]),
		.testTarget(
			name: "helloworldTests",
			dependencies: ["helloworld"]),
	]
)

因為函式庫的大小較大,建議網路速度較慢的讀者在這裏先回到 terminal 執行 swift build

要注意一旦編輯 Package.swift 檔後,必須使用主動儲存變更,XCode 才會更新專案,我們可以使用 File > Save 來主動儲存。

使用 SPMUtility 讀取 Arguments 與支援其他應用。

為了實現讀取 Arguments 的功能,我們要到 main.swift 編寫程式碼!

首先,通過 import Foundation,我們取得使用者輸入的 Arguments。

import Foundation
import SPMUtility

let arguments = ProcessInfo.processInfo.arguments[1...]

print("Hello, world!")

使用 ArgumentParser 使 Swift 可以讀取 Arguments。

let parser = ArgumentParser(usage: "<options>", overview: "A Swift command-line tool to say hello")
let nameArgument = parser.add(option: "--name", shortName: "-n", kind: String.self, usage: "The name to greeting")
let repeatArgument = parser.add(option: "--repeat", shortName: "-r", kind: Int.self, usage: "The repeat count of Hello")

我們建立了單一 Parser,加入兩個可用的參數,--name--repeat,透過 shortName 的參數建立各自的別名,kind 則建立指定的 Swift 型別。

接下來我們透過邏輯完成這個應用程式。

import SPMUtility
import Foundation

let arguments = ProcessInfo.processInfo.arguments[1...]

let parser = ArgumentParser(usage: "<options>", overview: "A Swift command-line tool to say hello")
let nameArgument = parser.add(option: "--name", shortName: "-n", kind: String.self, usage: "The name to greeting")
let repeatArgument = parser.add(option: "--repeat", shortName: "-r", kind: Int.self, usage: "The repeat count of Hello")

do {
    let parsedArguments = try parser.parse(Array(arguments))
    let name = parsedArguments.get(nameArgument) ?? "world"
    var repeatCount = parsedArguments.get(repeatArgument) ?? 0
	repeatCount = repeatCount > 0 ? repeatCount : 1
	var helloRepeat = ["Hello"]
	for _ in 1..<repeatCount {
		helloRepeat.append("hello")
	}
	let holloSentence = helloRepeat.joined(separator: ", ")
    print("\(holloSentence), \(name)")
} catch {
    print("helloworld greeting failed: \(error)")
}

現在,我們來測試看看!在 terminal 裡執行以下指令,你應該看到應用程式的結果。

$ swift run helloworld --name yu --repeat 3
Hello, hello, hello, yu

ArgumentParser 同時也提供 --help 的功能。

$ swift run swift run helloworld --help
OVERVIEW: A Swift command-line tool to say hello

USAGE: helloworld <options>

OPTIONS:
  --name, -n     The title to greeting
  --repeat, -r   The repeat count of Hello
  --help         Display available options

將 SPM 打包並安裝到 Unix 上

在經歷了各種測試後,我們的 helloworld 已經可以作為一個日常的使用工具,透過以下的方式,將執行檔安裝到 terminal 上。

$ swift build --configuration release
$ cp -f .build/release/helloworld /usr/local/bin/helloworld

如此一來,就可以使用了!

$ helloworld --help
OVERVIEW: A Swift command-line tool to say hello

USAGE: helloworld <options>

OPTIONS:
  --name, -n     The title to greeting
  --repeat, -r   The repeat count of Hello
  --help         Display available options

以上,就是如何製作一個CLI!

Tagged with: