Parsing file URLs with ArgumentParser

Hey folks!

Just spent a bit of time and moved our previous argument parsing using UserDefaults to ArgumentParser. First off - thanks to everyone who contributed, this is great!

Here's a PR (mostly moving implementation around, but replacing ~160 LOC with ~20 LOC for the actual parsing) for the implementation: https://github.com/firebase/firebase-ios-sdk/pull/4993

We wanted to deal with URLs specifically, so we're trying out this pattern:

struct Foo: ParsableCommand {
  @Option(help: "The file URL we want.",
          transform: URL.init(fileURLWithPath:))
  var pathToFile: URL

  mutating func validate() throws {
    // Verify the file actually exists.
    guard FileManager.default.fileExists(atPath: pathToFile.path) else {
      throw ValidationError("File does not exist at \(pathToFile.path)")
    }
  }

  func run() throws {
    // Do something with pathToFile...
  }
}

It's also nice because we can pass in relative paths this way and it'll expand automatically.

Any thoughts on improvements or gotchas I may not be thinking about? Thanks, I'm excited to move our other tools over as well!

3 Likes

Looks great to me! That’s just what the transform parameter and validate method are intended for.

1 Like

Just a thought: There’s some controversy related to using fileExists at this point, since you’ll have a race between your check and when it’s actually accessed. And the file might be there, but you might not have read access. And other related issues. And hence, some people would argue that you shouldn’t check at this point if the file exists, but rather just open the file and the handle any resulting error appropriately.

4 Likes

Very good points, thank you for pointing them out! That's a great point about attempting to open the file here - I'll look at doing so for our implementation as well.

1 Like