I am trying to create a utility to create a DMG from a given number of files.
That DMG will contain a number of files and for each file I have a mandatory
name plus an optional position within the DMG window plus an optional type.
As far as I know it is not possibility for the standard argument parser to parse the "file specifications". Am I correct or am I missing something here?
So I ended up by parsing the file specifications manually using custom code:
@Argument(
parsing: .unconditionalRemaining,
help: "Specify content in the form path [--position x y] [--type file|link]")
var args: [String]
And then in the run() method I will parse args manually.
One of the unwanted side-effects is that standard options like --verbose must now precede the arguments.
The way I’ve seen many other programs (not even necessarily Swift Argument Parser ones) do this is to combine all the information into a custom format in a single argument. For instance : is not generally valid in filenames so you could something like
I admit you lose some user experience in having to teach the custom format (especially if someone could specify just the link type and not the position, for instance), but it’s a trade-off between that and being able to specify the other arguments anywhere in the rest of the list.
Assuming any character other than NUL will never exist in a file name can lead to trouble.
The reason you don't normally see colon (:) in macOS file names is because the Hierarchical File System (HFS), the format used by Macs prior HFS+ and prior to APFS, used it as a path separator. For example, what you'd spell as /Users/alex/hello.swift in a Unix-y way would have been represented by HFS as something like Macintosh HD:Users:alex:hello.swift.
You can create a file with a colon in its name in Terminal. I just tested touch a:b now. It's worth noting that Finder shows that file's name as a/b — from a user's perspective, slashes are allowed but not colons, and Finder silently maps between them to actually use a colon in the name stored on disk.
Regardless, even if there are some corner-cases, both macOS and Linux use : as a path separator for things like your PATH, so in general it should be decently okay to use. Obviously not perfect, but it’s a common solution to this problem that other tools I’ve used have implemented successfully. Again, it’s a trade-off between being able to specify your arguments at any point in the command and having to deal with the user experience concerns introduced by the solution.
ArgumentParser doesn’t really support that kind of relationship between positional arguments and options/flags, so I don’t think there’s a much better way to handle what you’re trying to do. One thing I might do is to remove the .unconditionalRemaining parsing strategy, and instead call your command with the file specifications after a double-dash (--):