Skip to content

Commit 9cc02da

Browse files
committed
Replace SimpleCLI with Apple's Swift Argument Parser
1 parent d9a482a commit 9cc02da

File tree

3 files changed

+111
-90
lines changed

3 files changed

+111
-90
lines changed

Package.resolved

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ let package = Package(
1010
],
1111
dependencies: [
1212
// Dependencies declare other packages that this package depends on.
13-
.package(url: "https://github.com/lapfelix/SimpleCLI.git", from: "0.1.0"),
13+
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "0.0.1")
1414
],
1515
targets: [
1616
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
1717
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
1818
.target(
1919
name: "BluetoothConnector",
20-
dependencies: ["SimpleCLI"]),
20+
dependencies: [.product(name: "ArgumentParser", package: "swift-argument-parser"),]),
2121
.testTarget(
2222
name: "BluetoothConnectorTests",
2323
dependencies: ["BluetoothConnector"]),
Lines changed: 105 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import IOBluetooth
2-
import SimpleCLI
2+
import ArgumentParser
33

4-
func printHelp() {
5-
print(cliParser.helpString(CommandLine.arguments))
6-
print("\nGet the MAC address from the list below (if your device is missing, pair it with your computer first):");
4+
func getDeviceListHelpString() -> String {
5+
var helpString = "\nMAC Address missing. Get the MAC address from the list below (if your device is missing, pair it with your computer first):"
76
IOBluetoothDevice.pairedDevices().forEach({(device) in
87
guard let device = device as? IOBluetoothDevice,
98
let addressString = device.addressString,
109
let deviceName = device.name
1110
else { return }
12-
print("\(addressString) - \(deviceName)")
11+
helpString += "\n\(addressString) - \(deviceName)"
1312
})
13+
helpString += "\n"
14+
return helpString
1415
}
1516

1617
func printAndNotify(_ content: String, notify: Bool) {
@@ -46,101 +47,121 @@ func turnOnBluetoothIfNeeded(notify: Bool) {
4647
}
4748
}
4849

49-
let cliParser = SimpleCLI(configuration: [
50-
Argument(longName: "connect", shortName: "c", type: .keyOnly, defaultValue: "false"),
51-
Argument(longName: "disconnect", shortName: "d", type: .keyOnly, defaultValue: "false"),
52-
Argument(longName: "status", shortName: "s", type: .keyOnly, defaultValue: "false"),
53-
Argument(longName: "address", type: .valueOnly, obligatory: true, inputName: "00-00-00-00-00-00"),
54-
Argument(longName: "notify", shortName: "n", type: .keyOnly, defaultValue: "false"),
55-
])
56-
let dictionary = cliParser.parseArgs(CommandLine.arguments)
57-
58-
guard let deviceAddress = dictionary["address"] else {
59-
printHelp()
60-
exit(0)
61-
}
62-
63-
var notify = false
64-
if let notifyString = dictionary["notify"] {
65-
notify = Bool(notifyString) ?? false
66-
}
67-
68-
guard let bluetoothDevice = IOBluetoothDevice(addressString: deviceAddress) else {
69-
printAndNotify("Device not found", notify: notify)
70-
exit(-2)
71-
}
72-
73-
if !bluetoothDevice.isPaired() {
74-
printAndNotify("Not paired to device", notify: notify)
75-
exit(-4)
50+
enum ActionType {
51+
case Connection
52+
case Disconnect
7653
}
7754

78-
var connectOnly = false
79-
if let connectString = dictionary["connect"] {
80-
connectOnly = Bool(connectString) ?? false
81-
}
55+
func execute(macAddress: String, connectOnly: Bool, disconnectOnly: Bool, notify: Bool, statusOnly: Bool) {
56+
guard let bluetoothDevice = IOBluetoothDevice(addressString: macAddress) else {
57+
printAndNotify("Device not found", notify: notify)
58+
exit(-2)
59+
}
8260

83-
var disconnectOnly = false
84-
if let disconnectString = dictionary["disconnect"] {
85-
disconnectOnly = Bool(disconnectString) ?? false
86-
}
61+
if !bluetoothDevice.isPaired() {
62+
printAndNotify("Not paired to device", notify: notify)
63+
exit(-4)
64+
}
8765

88-
var statusOnly = false
89-
if let statusString = dictionary["status"] {
90-
statusOnly = Bool(statusString) ?? false
91-
}
66+
let alreadyConnected = bluetoothDevice.isConnected()
67+
let shouldConnect = (connectOnly
68+
|| (!connectOnly && !disconnectOnly && !alreadyConnected))
9269

93-
let alreadyConnected = bluetoothDevice.isConnected()
70+
if statusOnly {
71+
if alreadyConnected {
72+
print("Connected")
73+
}
74+
else {
75+
print("Disconnected")
76+
}
77+
exit(0)
78+
}
9479

95-
if statusOnly {
96-
if alreadyConnected {
97-
print("Connected")
80+
var error : IOReturn = -1
81+
var action : ActionType
82+
if shouldConnect {
83+
action = .Connection
84+
turnOnBluetoothIfNeeded(notify: notify)
85+
error = bluetoothDevice.openConnection()
9886
}
9987
else {
100-
print("Disconnected")
88+
action = .Disconnect
89+
error = bluetoothDevice.closeConnection()
90+
}
91+
92+
if error > 0 {
93+
printAndNotify("Error: \(action) failed", notify: notify)
94+
exit(-1)
95+
} else if notify {
96+
if action == .Connection && alreadyConnected {
97+
printAndNotify("Already connected", notify: notify)
98+
}
99+
else if action == .Disconnect && !alreadyConnected {
100+
printAndNotify("Already disconnected", notify: notify)
101+
}
102+
else {
103+
switch action {
104+
case .Connection:
105+
printAndNotify("Successfully connected", notify: notify)
106+
107+
case .Disconnect:
108+
printAndNotify("Successfully disconnected", notify: notify)
109+
}
110+
}
101111
}
102-
exit(0)
103112
}
104113

105-
var error : IOReturn = -1
114+
struct BluetoothConnector: ParsableCommand {
115+
@Flag(name: .shortAndLong, help: "Connect a device")
116+
var connect: Bool
106117

107-
enum ActionType {
108-
case Connection
109-
case Disconnect
110-
}
118+
@Flag(name: .shortAndLong, help: "Disconnect a device")
119+
var disconnect: Bool
111120

112-
var action : ActionType
121+
@Flag(name: .shortAndLong, help: "Get the status of a device")
122+
var status: Bool
113123

114-
let shouldConnect = (connectOnly
115-
|| (!connectOnly && !disconnectOnly && !alreadyConnected))
124+
@Flag(name: .shortAndLong, help: "Post a Notification Center notification")
125+
var notify: Bool
116126

117-
if shouldConnect {
118-
action = .Connection
119-
turnOnBluetoothIfNeeded(notify: notify)
120-
error = bluetoothDevice.openConnection()
121-
}
122-
else {
123-
action = .Disconnect
124-
error = bluetoothDevice.closeConnection()
125-
}
127+
@Argument(help: ArgumentHelp(
128+
"The MAC address of the device. Format: 00-00-00-00-00-00 or 000000000000",
129+
valueName: "MAC address"))
130+
var macAddress: String?
126131

127-
if error > 0 {
128-
printAndNotify("Error: \(action) failed", notify: notify)
129-
exit(-1)
130-
} else if notify {
131-
if action == .Connection && alreadyConnected {
132-
printAndNotify("Already connected", notify: notify)
133-
}
134-
else if action == .Disconnect && !alreadyConnected {
135-
printAndNotify("Already disconnected", notify: notify)
136-
}
137-
else {
138-
switch action {
139-
case .Connection:
140-
printAndNotify("Successfully connected", notify: notify)
141-
142-
case .Disconnect:
143-
printAndNotify("Successfully disconnected", notify: notify)
132+
static var configuration = CommandConfiguration(
133+
commandName: "BluetoothConnector",
134+
abstract: "Connect/disconnects Bluetooth devices.",
135+
discussion: "Default behavior is to toggle between connecting and disconnecting.")
136+
137+
mutating func validate() throws {
138+
guard connect != true || disconnect != true else {
139+
throw ValidationError("Can't connect and disconnect at once.")
140+
}
141+
142+
if status {
143+
guard connect == false else {
144+
throw ValidationError("Can't connect with status flag enabled.")
145+
}
146+
147+
guard disconnect == false else {
148+
throw ValidationError("Can't disconnect with status flag enabled.")
149+
}
150+
}
151+
152+
if let address = macAddress {
153+
if address.replacingOccurrences(of: "-", with: "").count != 12 {
154+
throw ValidationError("Invalid MAC address: \(address).")
155+
}
156+
}
157+
else {
158+
throw ValidationError(getDeviceListHelpString())
144159
}
145160
}
161+
162+
func run() throws {
163+
execute(macAddress: macAddress!, connectOnly: connect, disconnectOnly: disconnect, notify: notify, statusOnly: status)
164+
}
146165
}
166+
167+
BluetoothConnector.main()

0 commit comments

Comments
 (0)