Issue #559
public class GetDestinations {
    public init() {}
    public func getAvailable(workflow: Workflow) throws -> [Destination] {
        let processHandler = DefaultProcessHandler(filter: { $0.starts(with: "name=") })
        let string = try CommandLine().runBash(
            workflow: workflow,
            program: "xcrun simctl",
            arguments: [
                "list",
                "devices",
                "-j"
            ],
            processHandler: processHandler
        )
        guard let data = string.data(using: .utf8) else {
            throw PumaError.invalid
        }
        let response: Response = try JSONDecoder().decode(Response.self, from: data)
        let devicesWithOS: [DeviceWithOS] = response.devices.flatMap({ key, value in
            return value.map({ DeviceWithOS(device: $0, os: key) })
        })
        let destinations: [Destination] = try devicesWithOS
            .filter({ withOS in
                return withOS.device.isAvailable
            })
            .compactMap({ withOS in
                guard
                    let platform = self.platform(withOS: withOS),
                    let os = try self.os(withOS: withOS)
                else {
                    return  nil
                }
                var destination = Destination(
                    name: withOS.device.name,
                    platform: platform,
                    os: os
                )
                destination.id = withOS.device.udid
                return destination
            })
        return destinations
    }
    func findId(workflow: Workflow, destination: Destination) throws -> String? {
        let availableDestinations = try self.getAvailable(workflow: workflow)
        return availableDestinations.first(where: { $0 == destination })?.id
    }
    // MARK: - Private
    private func platform(withOS: DeviceWithOS) -> String? {
        let list: [String] = [
            Destination.Platform.iOS,
            Destination.Platform.watchOS,
            Destination.Platform.macOS,
            Destination.Platform.tvOS,
        ]
        return list.first(where: { withOS.os.contains($0) })
    }
    // com.apple.CoreSimulator.SimRuntime.iOS-13-2
    private func os(withOS: DeviceWithOS) throws -> String? {
        guard let string = try withOS.os.matches(pattern: #"(-\d+)+"#).first else {
            return nil
        }
        return string.dropFirst().replacingOccurrences(of: "-", with: ".")
    }
}
private struct Response: Decodable {
    let devices: [String: [Device]]
}
private struct Device: Decodable {
    let state: String
    let name: String
    let udid: String
    let isAvailable: Bool
}
private struct DeviceWithOS {
    let device: Device
    let os: String
}
Start the conversation