Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/sebsto/clilib
A library to build command line tools in Swift
https://github.com/sebsto/clilib
Last synced: 6 days ago
JSON representation
A library to build command line tools in Swift
- Host: GitHub
- URL: https://github.com/sebsto/clilib
- Owner: sebsto
- License: apache-2.0
- Created: 2022-09-26T23:07:48.000Z (about 2 years ago)
- Default Branch: main
- Last Pushed: 2023-09-30T03:00:32.000Z (about 1 year ago)
- Last Synced: 2023-09-30T05:01:39.319Z (about 1 year ago)
- Language: Swift
- Size: 23.4 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
[![Build And Test](https://github.com/sebsto/CLIlib/actions/workflows/build_and_test.yml/badge.svg)](https://github.com/sebsto/CLIlib/actions/workflows/build_and_test.yml)
![language](https://img.shields.io/badge/swift-5.7-blue)
![platform](https://img.shields.io/badge/platform-macOS-green)
[![license](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)# CLIlib
A set of classes to build command-line (CLI) applications in Swift.
## User I/O
### Displaying information to users
```swift
public protocol DisplayProtocol {
func display(_ msg: String, terminator: String)
}
```### Requesting information from users
```swift
public protocol ReadLineProtocol {
func readLine(prompt: String, silent: Bool) -> String?
}
```### Example usage
```swift
// the display implementation to display messages to users, allows to inject a mock for testing
var display: DisplayProtocol = Display()// the input function to collect user entry, allows to inject a mocked implementation for testing
var input: ReadLineProtocol = ReadLine()display("Retrieving Apple Developer Portal credentials...")
guard let username = input.readLine(prompt: "⌨️ Enter your Apple ID username: ", silent: false) else {
throw CLIError.invalidInput
}guard let password = input.readLine(prompt: "⌨️ Enter your Apple ID password: ", silent: true) else {
throw CLIError.invalidInput
}enum CLIError: Error {
case invalidInput
}
```## ProgressBar
```swift
public enum ProgressBarType {
// 30% [============--------------------]
case percentProgressAnimation
// [ 1/2 ]
case countingProgressAnimation// [ 1/2 ]
// [ 2/2 ]
case countingProgressAnimationMultiLine
}
``````swift
public protocol ProgressUpdateProtocol {
/// Update the animation with a new step.
/// - Parameters:
/// - step: The index of the operation's current step.
/// - total: The total number of steps before the operation is complete.
/// - text: The description of the current step.
func update(step: Int, total: Int, text: String)/// Complete the animation.
/// - Parameters:
/// - success: Defines if the operation the animation represents was succesful.
func complete(success: Bool)/// Clear the animation.
func clear()
}
```### Example Usage
```swift
let stream: OutputBuffer = FileHandle.standardOutput
let progress = ProgressBar(output: stream, progressBarType: .percentProgressAnimation, title: "Downloading...")
progress.update(1, 10, "Downloading...")
...
progress.update(10, 10, "Downloading...")
progress.complete(true)
```## Shell
Asynchronously run shell commands.
```swift
public protocol AsyncShellProtocol: ShellProtocol {
func run(_ command: String,
onCompletion: ((Process) -> Void)?,
onOutput: ((String) -> Void)?,
onError: ((String) -> Void)?
) throws -> Process
}
```### Example Usage
```swift
public func run(_ command: String) throws -> ShellOutput {var stdOutBuffer: String = ""
var stdErrBuffer: String = ""
var result: ShellOutput?
let sema: DispatchSemaphoreProtocol = DispatchSemaphore( value: 0 )
let shell = AsyncShell()
let process = try shell.run(command,
onCompletion: { process in
result = ShellOutput(out: stdOutBuffer, err: stdErrBuffer, code: process.terminationStatus)
_ = sema.signal()
},
onOutput: { string in
stdOutBuffer += string
},
onError: { string in
stdErrBuffer += string
})
process.waitUntilExit()
// wait for onCompletion callback to finish
sema.wait()
guard let res = result else {
fatalError("Process finished but there is no output!")
}
return res
}
```