tests/test-arbitraryfilectx.t
author Gregory Szorc <gregory.szorc@gmail.com>
Tue, 10 Apr 2018 14:29:15 -0700
changeset 37557 734515aca84d
parent 37318 9954d0e2ad00
child 41359 5361f9ed8a30
permissions -rw-r--r--
wireproto: define and implement HTTP handshake to upgrade protocol When clients connect to repositories over HTTP, they issue a request to the well-known URL "?cmd=capabilities" to fetch the repository capabilities. This is the handshake portion of the HTTP protocol. This commit defines a mechanism to use that HTTP request to return information about modern server features. If a client sends an X-HgUpgrade-* header containing a list of client-supported API names, the server responds with a response containing information about available services. This includes the normal capabilities string. So if the server doesn't support any newer services, the client can easily fall back. By advertising supported services from clients, server operators can see and log what client support exists in the wild. This will also help with debugging. The response contains the base path to API services. We know there are potential issues with the <repo>/api/ URL space conflicting with hgwebdir and subrepos. By making the API URL dynamic from the perspective of the client, the URL for APIs is not subject to backwards compatibility concerns - at least as long as a ?cmd=capabilities request is made. We've also defined the ``cbor`` client capability for the X-HgProto-* header. This MUST be sent in order to get the modern response from "?cmd=capabilities". During implementation, I initially always sent an application/mercurial-cbor response. However, the handshake mechanism will be more future compatible if the client is in charge of which formats to request. We already perform content negotiation from X-HgProto-*, so keying off this for the capabilities response feels appropriate. In addition, I initially used application/cbor. However, it is conceivable that a non-Mercurial server could serve application/cbor. To rule out this possibility, I've invented a new media type that is Mercurial specific and can't be confused for generic CBOR. Differential Revision: https://phab.mercurial-scm.org/D3242

Setup:
  $ cat > eval.py <<EOF
  > from __future__ import absolute_import
  > import filecmp
  > from mercurial import commands, context, pycompat, registrar
  > cmdtable = {}
  > command = registrar.command(cmdtable)
  > @command(b'eval', [], b'hg eval CMD')
  > def eval_(ui, repo, *cmds, **opts):
  >     cmd = b" ".join(cmds)
  >     res = pycompat.bytestr(eval(cmd, globals(), locals()))
  >     ui.warn(b"%s" % res)
  > EOF

  $ echo "[extensions]" >> $HGRCPATH
  $ echo "eval=`pwd`/eval.py" >> $HGRCPATH

Arbitraryfilectx.cmp does not follow symlinks:
  $ mkdir case1
  $ cd case1
  $ hg init
#if symlink
  $ printf "A" > real_A
  $ printf "foo" > A
  $ printf "foo" > B
  $ ln -s A sym_A
  $ hg add .
  adding A
  adding B
  adding real_A
  adding sym_A
  $ hg commit -m "base"
#else
  $ hg import -q --bypass - <<EOF
  > # HG changeset patch
  > # User test
  > # Date 0 0
  > base
  > 
  > diff --git a/A b/A
  > new file mode 100644
  > --- /dev/null
  > +++ b/A
  > @@ -0,0 +1,1 @@
  > +foo
  > \ No newline at end of file
  > diff --git a/B b/B
  > new file mode 100644
  > --- /dev/null
  > +++ b/B
  > @@ -0,0 +1,1 @@
  > +foo
  > \ No newline at end of file
  > diff --git a/real_A b/real_A
  > new file mode 100644
  > --- /dev/null
  > +++ b/real_A
  > @@ -0,0 +1,1 @@
  > +A
  > \ No newline at end of file
  > diff --git a/sym_A b/sym_A
  > new file mode 120000
  > --- /dev/null
  > +++ b/sym_A
  > @@ -0,0 +1,1 @@
  > +A
  > \ No newline at end of file
  > EOF
  $ hg up -q
#endif

These files are different and should return True (different):
(Note that filecmp.cmp's return semantics are inverted from ours, so we invert
for simplicity):
  $ hg eval "context.arbitraryfilectx('A', repo).cmp(repo[None]['real_A'])"
  True (no-eol)
  $ hg eval "not filecmp.cmp('A', 'real_A')"
  True (no-eol)

These files are identical and should return False (same):
  $ hg eval "context.arbitraryfilectx('A', repo).cmp(repo[None]['A'])"
  False (no-eol)
  $ hg eval "context.arbitraryfilectx('A', repo).cmp(repo[None]['B'])"
  False (no-eol)
  $ hg eval "not filecmp.cmp('A', 'B')"
  False (no-eol)

This comparison should also return False, since A and sym_A are substantially
the same in the eyes of ``filectx.cmp``, which looks at data only.
  $ hg eval "context.arbitraryfilectx('real_A', repo).cmp(repo[None]['sym_A'])"
  False (no-eol)

A naive use of filecmp on those two would wrongly return True, since it follows
the symlink to "A", which has different contents.
#if symlink
  $ hg eval "not filecmp.cmp('real_A', 'sym_A')"
  True (no-eol)
#else
  $ hg eval "not filecmp.cmp('real_A', 'sym_A')"
  False (no-eol)
#endif