[PATCH python-hglib v2] Add feature to allow hglib user to get call backs for prompts, output
Barry Scott
barry at barrys-emacs.org
Mon Oct 24 06:04:39 EDT 2016
> On 23 Oct 2016, at 10:53, Yuya Nishihara <yuya at tcha.org> wrote:
>
> On Sat, 22 Oct 2016 18:37:07 +0100, Barry A. Scott wrote:
>> # HG changeset patch
>> # User Barry A. Scott <barry at barrys-emacs.org <mailto:barry at barrys-emacs.org>>
>> # Date 1477157573 -3600
>> # Sat Oct 22 18:32:53 2016 +0100
>> # Node ID 12c96b1d8dfff261f91ed010cc59ce57bfa63b4f
>> # Parent 6f15cb7cc9cb4427f35c60080f85dbf4ca5abd10
>> Add feature to allow hglib user to get call backs for prompts, output
>> and errors.
>
> "topic: short summary line with no trailing period"
>
> https://www.mercurial-scm.org/wiki/ContributingChanges#Patch_descriptions <https://www.mercurial-scm.org/wiki/ContributingChanges#Patch_descriptions>
Will fix. (I did not notice until it was sent).
>
>> setcbout(cbout), setcberr(cberr) and setcbprompt(cbprompt) are used to
>> set the call back function used by the hgclient class. cb stands for
>> call back.
>>
>> cbout is a function that will be called with the stdout data of the
>> command as it runs. cbout is called with output as it is made available,
>> which can be as partial lines or multiple lines.
>>
>> cberr is a function that will be called with the stderr data of the
>> command as it runs. cberr is called with output as it is made available,
>> which can be as partial lines or multiple lines.
>>
>> Command that make remote connects can prompt for username and password
>> for HTTP/HTTPS connections.
>>
>> cbprompt is called when hgclient need a response to a prompt from the
>> server. It receives the max number of bytes to return and the contents
>> of stdout received so far. The last text sent to either cbout or cberr
>> will contain the prompt text itself.
>>
>> init() has been added to hgclient to allow use of setcbXXX functions
>> with init(). The init() code is based on the version in __init__.py.
>
> So this patch contains 3 different things. Can you send them as separate
> patches?
>
> - add callbacks
> - change clone() behavior (which seems wrong)
> - add init()
Yes and no. Both clone and init cannot be used with the call backs with these changes.
I can package as 3 patches that build on each other. But in my mind these are linked.
I will do as you advise, please confirm 3 patches required.
>
>> + def setcbout(self, cbout):
>> + """
>> + cbout is a function that will be called with the stdout data of
>> + the command as it runs. Call with None to stop getting call backs.
>> + """
>> + self._cbout = cbout
>> +
>> + def setcberr(self, cberr):
>> + """
>> + cberr is a function that will be called with the stderr data of
>> + the command as it runs.Call with None to stop getting call backs.
>> + """
>> + self._cberr = cberr
>> +
>> + def setcbprompt(self, cbprompt):
>> + """
>> + cbprompt is used to reply to prompts by the server
>> + It receives the max number of bytes to return and the
>> + contents of stdout received so far.
>> +
>> + Call with None to stop getting call backs.
>> +
>> + cbprompt is never called from merge() or import_()
>> + which already handle the prompt.
>> + """
>> + self._cbprompt = cbprompt
>
> Nit: The "cb" prefix doesn't make sense here because there's little possibility
> of name conflicts.
True but it is descriptive.
>
> And I think your setprotocoltrace() covers setcbout/err. Do we still need them?
They solve two distinct problems.
protocol tracing provides a way to see the low level, almost unprocessed messages between client and server.
Its purpose is to allow inspection and debugging of the protocol.
cbout and cderr provide a user of hglib with the post processed output and error information.
In production my GUI will use cdout and cderr often, but never protocol trace. But when I cannot
figure out what is happening I turn on protocol trace to get an insight into how hglib works.
That is, for example, how I found that password: is sent on the āeā channel.
Conclusion yes we need both.
>> def clone(self, source=b('.'), dest=None, branch=None, updaterev=None,
>> - revrange=None):
>> + revrange=None, pull=False, uncompressed=False, ssh=None,
>> + remotecmd=None, insecure=False, encoding=None, configs=None):
>> """
>> Create a copy of an existing repository specified by source in a new
>> directory dest.
>> @@ -536,9 +584,30 @@
>> revrange - include the specified changeset
>> """
>> args = cmdbuilder(b('clone'), source, dest, b=branch,
>> - u=updaterev, r=revrange)
>> + u=updaterev, r=revrange, pull=pull,
>> + uncompresses=uncompressed, e=ssh,
>> + remotecmd=remotecmd, insecure=insecure)
>> self.rawcommand(args)
>>
>> + if self._path is None:
>> + self._path = dest
>> + # become the client for the cloned hg repo
>> + self.close()
>> + self._args += ['-R', dest]
>> + self.open()
>
> This changes the behavior of clone(), but hglib should provide a stable API.
It is a backward compatible extension of the API by adding what hglib provided in the __init__.py
version of clone.
> Also, dest may be a remote (ssh) path.
I do not see how my patch breaks things in that case. I do not assume the
dest is a local path.
>
>> + def init(self, dest, ssh=None, remotecmd=None, insecure=False,
>> + encoding=None, configs=None):
>> + args = util.cmdbuilder(b'init', dest, e=ssh, remotecmd=remotecmd,
>> + insecure=insecure)
>> + self.rawcommand(args)
>> +
>> + # become the client for this new hg repo
>> + self._path = dest
>> + self.close()
>> + self._args += ['-R', dest]
>> + self.open()
>
> Same here, dest may be a remote path.
>
> IMHO, methods of hgclient shouldn't have such magic. Instead, we can provide
> a utility function on top of plain init(), e.g.
>
> client = client.hgclient()
> client.init(dest)
> return open(dest)
That is semantically identical to my patch.
See __init__.py:11 and client.py:49 of the unpatched source.
However that does not work for the call back case. Here is how I use init.
c = hglib.open( None )
c.setcbout(cbout)
c.setcberr(cbout)
c.init(b'path/for/new/repo')
c.status() # works on new repo
This works for the local path case. And this for clone:
c = hglib.open( None )
c.setcbout(cbout)
c.setcberr(cbout)
c.setcbprompt(cbprompt)
c.clone(b'http://example.com/hgrepo', b'path/for/new/repo <http://example.com/hgrepo',%20b'path/for/new/repo>')
c.status() # works on new repo
>
> Maybe we can provide it as a replacement for hglib.init().
>
> def init():
> try:
> _initbyhgclient()
> except 'exception raised if command server failed to start':
> falls back to the original init()
I choose to leave the hglib.init and hglib.clone code untouched for as its uses of it
cannot care about call backs.
Barry
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.mercurial-scm.org/pipermail/mercurial-devel/attachments/20161024/6780b803/attachment.html>
More information about the Mercurial-devel
mailing list