🔥 /SwiftSlash/ 🔥

完全使用 Async/Await 构建的并发 Shell 框架

文档

现在已使用 swift-docc 完整记录!

为什么选择 SwiftSlash?

高效、并发、简单。

SwiftSlash 的开发是为了解决所有现有 shell 框架的缺点。这些框架包括 SwiftCLIShellShellOutShellKitWork 以及广受欢迎的 SwiftShell。这些框架在其公共 GitHub 存储库中的累积星数 > 1,874。

这些现有框架的致命弱点是它们内部使用了 Foundation 自身的 Process 类,这是一个内存占用量大的类,没有考虑到并发或复杂的使用场景。对于单个、串行化的执行,这些框架可以正常运行(尽管会泄漏内存)。但是,在高负载下,由于 Process 的缺点,所有这些框架都难以维持稳定。

SwiftSlash 的设计从一开始就有意地解决了这些现有框架的缺点,因此,特意不使用 Process 类。 从 3.0 版本开始,SwiftSlash 是第一个完全使用 Swift async/await 并发范例构建的并发 shell 框架。 在 2.2.2 版本之前,SwiftSlash 使用 Grand Central Dispatch 作为内部并发范例。

由于以根本不同的引擎作为 SwiftSlash 的核心,与其他框架相比,客观的改进如下

最后,SwiftSlash 非常易于使用,因为它实现了一个严格而简单的公共 API。

开始使用

Command 实现了一个便捷函数 runSync(),这是一种无需设置或 I/O 处理即可执行进程的简单方法。

import SwiftSlash

// EXAMPLE: check the systems ZFS version and print the first line of the output

let commandResult:CommandResult = try await Command(bash:"zfs --version").runSync()

//check the exit code
if commandResult.exitCode == 0 {

	//print the first line of output
	print("Found ZFS version: \( String(data:commandResult.stdout[0], encoding:.utf8) )")
}

通过 ProcessInterface 实现完整功能

ProcessInterface 是一个强大而灵活的类,它是 SwfitSlash 框架的基础 API。无论您的进程需要同步还是异步处理解析或未解析的数据,ProcessInterface 都为定义此类需求提供了一个一致的平台。

/*
EXAMPLE: query the system for any zfs datasets that might be imported.
			stdout: parse as lines
			stderr: unparsed, raw data will be sent through the stream as it becomes available

*/

//define the command you'd like to run
let zfsDatasetsCommand:Command = Command(bash:"zfs list -t dataset")

//pass the command structure to a new ProcessInterface. in this example, stdout will be parsed into lines with the lf byte, and stderr will be unparsed (raw data will be passed into the stream)
let zfsProcessInterface = ProcessInterface(command:zfsDatasetsCommand, stdout:.active(.lf), stderr:.active(.unparsedRaw))

//launch the process. if you are running many concurrent processes (using most of the available resources), this is where your process will be queued until there are enough resources to support the launched process.
try await zfsProcessInterface.launch()

//handle lines of stdout as they come in
var datasetLines = [Data]()
for await outputLine in await zfsProcessInterface.stdout {
	guard let outputLineString = String(data: outputLine, encoding: .utf8) else { continue }
	print("dataset found: \(outputLineString)")
	datasetLines.append(outputLine)
}

//build the blob of stderr data if any was passed
var stderrBlob = Data()
for await stderrChunk in await zfsProcessInterface.stderr {
	print("\(stderrChunk.count) bytes were sent through stderr")
	stderrBlob += stderrChunk
}

//data can be written to stdin after a process is launched, like so...
zfsProcessInterface.write(stdin:"hello".data(using:.utf8)!)

//retrieve the exit code of the process.
let exitCode = try await zfsProcessInterface.exitCode()

if (exitCode == 0) {
	//do work based on success
} else {
	//do work based on error
}

许可

SwiftSlash 在 MIT 许可证下提供,并且不提供任何保证。请参阅 LICENSE。

联系方式

如有疑问,请通过 Twitter 联系 @tannerdsilva