Spinoff of #289 but more specifically, #294. Also dovetails with #368 re: the possible need for the responses configuration being much more than a simple call/response dict.
sudo (and many other prompt situations) can be handled via the naive implementation of autoresponding from #289: see string, respond with string, done.
However, in sudo's case at least, this can lead to annoying cases where an incorrect sudo password results in responding to the same prompt over and over until the remote sudoers config's passwd_tries number of tries is exceeded.
In Fabric v1, the authentication machinery was hardwired to look out for sudo's Sorry, try again response and to raise a failure flag in that case (which then affected the rest of the flow, typically by re-prompting the console user).
Sorry, try again
It would be nice to extend the autoresponse functionality so that sort of 'stateful' setup is possible, though I suspect it would be pretty complex.
What's needed for the sudo use case to work better:
"Sorry, try again"
responses['sudo'] = respond_to_prompt(trigger='sudo password:', response='mypassword', failure='Sorry, try again')
Realized while quickly trialing this that I was confusing regular callbacks with generators/coroutines, and also that the latter don't work well for this because the caller (the output handler) needs a response to the stream data it's passing in, not the previous stream data (which is what would happen with a loop + data = yield response or similar).
data = yield response
To properly track state, I think we need bona fide objects + methods here. Probably cleaner / easier to share/reuse anyways?
Using a basic object seems to work well, tho I took out the threadlocal indices (because each obj can now store its own index) and surprise, that's no longer threadsafe. So these Responder (off the cuff name) objects need to be made thread-safe / thread-distinct, e.g.:
Made the API StreamWatcher + .submit, seems general enough, shrug. TODO:
Start generalizing prompt response stuff re #369.
Created real-enough watcher API and started using it internally.
Still needs surfacing at top of public API
This has been done for a while now; some notes about it are in the end of #294 because I'm kind of dumb.
Changelog re #369, closes #369