Hi folks! Something you see in a lot of command-line tools is the ability to request information from a running process via a platform-specific mechanism:
On Apple platforms, FreeBSD, and OpenBSD, by sending SIGINFO to the process or by pressing Ctrl+T in the Terminal application.
On Linux, by sending the SIGUSR1 signal to the process.
On Windows, by pressing Ctrl+Break in the Terminal application.
I've been working on implementing support for this functionality in Swift Argument Parser here. If merged, Swift Argument Parser users would be able to add this functionality by making their root command types conform to the new InfoProvidingParsableCommand protocol. For example:
Heh, indeed. Swift Argument Parser is the de facto TUI component in the Swift toolchain right now, so I'd sort of also expect it to eventually provide other TUI-oriented stuff like ANSI escape code support.
(While there's nothing here that must be implemented in Swift Argument Parser, I also wouldn't expect us to spin up a whole new Swift package just for this functionality.)
Why not? I feel like in the Swift ecosystem we're often ignoring the benefits of having small packages that just do a few things very well. Otherwise, you end up with kitchen-sink packages like swift-tools-support-core (which fortunately has had work done to reduce it).
(This is ignoring institutional overhead that goes into creating a new GitHub repository under an official organization, which might be quite a lot.)
I think ProcessInfo should grow some API to provide signal handlers, of which SIGUSR1 could be one such handler. I don't think that's directly relevant to this proposal though, since the implementation of the handler is not part of the API.
It feels weird to me to have a method called "provideInfo()" that doesn't have a return value. What am I providing, if there's nothing to return? If you want the method to print stuff, then perhaps calling it printInfo() makes more sense. However, I think I would advocate instead for changing it provideInfo() async throws -> String and make the handler itself responsible for printing. The command is providing the details; it's the handler's job to decide what to do with it.
There's really not enough here to justify a dedicated package. You could try to tie this to a larger TUI feature as I suggested, but nobody's building that. So yeah, it's a one-off.
There's already API in libdispatch for adding signal handlers, so I'm not sure that there's much reason for Foundation to also add equivalent API. But that's a discussion for the Foundation code owners, probably.
@jrose@allevato I'm curious what you each think about ArgumentParser introducing a CancellableCommand protocol with no requirements, but was just used to configure SIGINT to call Task.cancel() on the top level task?
Would you think that should or should not be a feature of ArgumentParser? What functionality do you think would be in another package, etc?
FWIW this is not at all hypothetical, if we were to adopt @grynspan's proposal in some form, this would likely follow shortly after.
I'd love to see a library like this be more standalone. If I were making a server, I might have very few command line needs, and so not want to use ArgumentParser. Equally, I might be trying to stick to Swift concurrency, so including libdispatch would seem excessive. It might even have some application in the embedded Linux space.
UnixSignalsSequence looks interesting.
On the other hand, the signals facilities might be highly over designed and just handling a few bits of it as needed might be the right way. I think I've never had more than 3 signal handlers in any of my code.
Personally I think these are all reasonable utilities for a package called CommandLineKit or something. Is ArgumentParser secretly CommandLineKit with backward-compatibility concerns?
Some possible considerations:
Do people use ArgumentParser for non-command-line purposes? Enough to sway the development of the package?
Is it better from a client perspective to depend on a few large packages or many small packages?
Do these new utilities require additional dependencies? Seems like these two probably don't, but maybe some future ones will.
Do people use ArgumentParser for non-command-line purposes? Enough to sway the development of the package?
IMO ArgumentParser kinda already is CommandLineKit by virtue of owning @main for 99% of users. That said, I personally have also used it to implement simple consoles for some apps, so I wouldn't necessarily want it to only be used for CLI entry points.
Is it better from a client perspective to depend on a few large packages or many small packages?
As a maintainer, fewer repos to manage is a blessing. Having 10 dependabot PRs to review and ensure I didn't accidentally do something stupid is personally very fatiguing. Clearly not a "client's" perspective.
I do think as a user being able to pin 1 dep and not have to think about a big web of dependencies is a bit nicer?
Do these new utilities require additional dependencies? Seems like these two probably don't, but maybe some future ones will.
Swift Concurrency is implemented atop libdispatch, so you're "paying for" it anyway.
I'm sure somebody does, but the primary use case is, by definition, interpreting command-line arguments and running a program based on them. Being able to query (or, yes, cancel) that program does fall out naturally from that IMHO.
Realistically, the Swift project leans toward fewer larger packages, not more smaller ones.
I'm not really sure how to interpret that. I'm not adding dependencies here (libdispatch is already an implicit dependency, but we could dodge it if we really wanted to.) Yes, somebody could propose some feature in the future that has other dependencies, but that's probably a vacuous statement (no offence!)
This is just a current state. There is work in progress to make this no longer the case on non Darwin platforms and we should not expect that the executors are always backed by Dispatch.
I just want to make sure we are not tying ArgumentParser to Dispatch here.
Talking about the pitch, I think it makes sense. ArgumentParser is arguably a misnomer since the package does way more than that. The proposed changes also don't tie ArgumentParser to Dispatch even if it uses the signal sources initially. I can imagine in the future that this might be something that the default executors offers.
I think this would be super useful. But I’m not convinced this is the right “home”. ArgumentParser is about, well, parsing arguments. And this proposal is something else.