Detect errors in the unprivileged part of extend.py

If run as root, extend.py starts a child process, in which privileges are
dropped, to run the --fetch and --build stages.  Failures were not
propagated from this child process, meaning the overall process continued
anyway, most likely doing the wrong thing.
Use the correct SHA-1 when constructing v8-jsshell cache file path

The current sub-module SHA-1 checked out in the repository in which the
tests were run was used, but this is wrong if --commit is used to override
the tested commit, and also wrong if extend() runs before upgrade().

Keep track of which commit is current installed as 'self.current_commit',
and use that when constructing the cache file path.
Check if extend.py exists in the correct commit in check_extend()

Add 'self.tested_commit' which is the same as 'self.upgrade_commit' if
we're upgrading, and otherwise 'self.install_commit', and thus the commit
we're ultimately testing against.

Use this instead of 'self.install_commit' as the commit to check for
extend.py existence, unless 'pre_upgrade' is true.
Run "git submodule update --recursive" before upgrade.py

Necessary when upgrading past a commit that changes a sub-module pointer,
since upgrade.py otherwise complains about the repository having local
modifications.
Disable v8-jsshell caching if upgrading the v8-jsshell sub-module

If the v8-jsshell sub-module is modified in an upgrade, upgrade.py runs
extend.py, and "extend.py --fetch" fails if we used a cached v8-jsshell,
since the sub-module directory isn't empty then (we copy the cached
executable into it.)

It's meaningful to test the (automatic) incremental recompilation of
v8-jsshell that happens as part of the upgrade, so simply disable the
caching in this case.

This means that the testing of such commits becomes quite expensive, but
this should be sufficiently offset by the fact that sub-module updates
are rare.
Propagate --headless argument from upgrade.py to extend.py
Pass --libcurl-flavor=gnutls argument to extend.py when testing

This allows better testing coverage (the default is to not install a
libcurl flavor, meaning the v8-jsshell executable has no URL loading
support.)

Also, the libcurl-gnutls-dev package is typically installed in the VMs
used for testing when running with the "with-prereqs" snapshot.
Redirect "git cat-file --batch" process's stderr

Not doing so leads to a situation where Communicate.run() (communicate.py)
ends up waiting for the stdout/stderr pipes to EOF indefinitely, since the
Git process keeps the stderr pipe (which it then inherited from the parent
extension process) open.  This combined with an unclean extension process
shutdown where the Git process was not terminated would lead to a sort of
deadlock, where Communicate.run() waited until it timed out.

Nothing it is typically written to stderr; "git cat-file --batch" writes
normal error messages ("missing object" and such) to stdout.
Fix leaking "git cat-file --batch" processes

When an extension process shuts down "uncleanly" (i.e. without killing its
"git cat-file --batch" processes first,) those Git processes where left
alive indefinitely.  The reason for that was that a reference to the
writing end of the pipe used as Git's stdin was inherited into the child
process and thus never fully closed.

Avoid this by setting the FD_CLOEXEC flag on the file descriptor.

Also update the v8-jsshell submodule pointer to the commit that adds the
IO.File.setCloseOnExec() method that we use to do that.
Improve KeyboardInterrupt handling in testing framework

Testing should be aborted.  But in practice (with recent changes) only
the current top-level test group was aborted.

Also, the "Testing aborted." error message was logged immediately, and
then followed by various clean-up logging, and the test summary (which
included the "error" that testing was aborted in the "Errors logged"
counter.)  Re-arrange so that there is no test summary, and so that the
"Testing aborted." error message is the last thing logged, for clarity.