Propagating errors from ParsableCommand from an iOS app instead of a CLI application

I've found ArgumentParser extremely useful as I am working on a CLI iOS app that takes commands as input. I'm using this module to parse commands that users write into the app. I've described, as an example, the SSH command that would have the following format.

struct SSHCommand: ParsableCommand {
  
  @Option(name:  [.customLong("port"), .customShort("P")],
          default: "22",
          help: "Specifies the port to connect to on the remote host.")
  var port: String
  
  @Argument(help: "user@host")
  var host: String
  
  var username: String {
    get {
      
      if host.contains("@") {
        return host.components(separatedBy: "@")[0]
      } else {
        guard let hostName = SSHCommons.getHosts(by: host.components(separatedBy: ":")[0]) else {
          return ""
        }
        
        return hostName.user!
      }
    }
  }
  
  var remoteHost: String {
    get {
      
      if host.contains("@") {
        return host.components(separatedBy: "@")[1].components(separatedBy: ":")[0]
      } else {
        guard let hostName = SSHCommons.getHosts(by: host.components(separatedBy: ":")[0]) else {
          return ""
        }
        
        return hostName.hostName!
      }
    }
  }
  
  func run() throws {
    
  }
  
  func validate() throws {
    
    if host == nil || host.count == 0 {
      throw  ValidationError("Missing '<host>'")
    }
    
  }
}

This won't be run from the console but on an app validating the command input,

do {  
    sshCommand = try SSHCommand.parse(("ssh host -p 22".components(separatedBy: " "))      
} catch {
    print(message: error.localizedDescription)
}

It all runs okay but I'd like to prompt the user a descriptive error in the case of running a command such as ssh stating that it's missing a host to connect to.

I am having trouble propagating the validation errors such as ValidationError("Missing '<host>'") to be shown in the app. As far as I know that error would propagate through the screen an be shown if the app was a CLI application but in this case I'm at a loss. When the error is thrown in the catch block its type is not of ValidationError but ArgumentParser.CommandError which is not made publicly available in the Package.

Is there a guide on how to show the user this kind of informative errors when using ArgumentParser in an app instead of in a CLI app?

Your ParsableCommand type has a few static methods that can be used for getting information about errors:

do {  
    sshCommand = try SSHCommand.parse(("ssh host -p 22".components(separatedBy: " "))      
} catch {
    let message = SSHCommand.message(for: error)
    // or let message = SSHCommand.fullMessage(for: error)
    print(message)
}

You can also find out if the error represents a success state, a validation error, or another error by calling SSHCommand.exitCode(for: error).

I don't know how I could have missed this, thank you for tuning in Nate!

1 Like