When --pager=on is given, dispatch.py spawns a pager before setting up color.
If the pager failed to launch, ui.pageractive was left set to True, so color
configured itself based on 'color.pagermode'. A typical MSYS setting would be
'color.mode=auto, color.pagermode=ansi'. In the failure case, this would print
a warning, disable the pager, and then print the raw ANSI codes to the terminal.
Care needs to be taken, because it appears that leaving ui.pageractive=True was
the only thing that prevented an attempt at running the pager again from inside
the command. This results in a double warning message, so pager is simply
disabled on failure.
The ui config settings didn't need to be moved to fix this, but it seemed like
the right thing to do for consistency.
The next patches will convert environ to raw config items, and insert the
config items between systemrcpath and userrcpath. This patch teaches
rccomponents to return the type information so the caller could distinguish
between "path" and raw config "items".
As discussed at [1], the logic around "actual config"s seem to be
non-trivial enough that it's worth a new module.
This patch creates the module and move "scmutil.*rcpath" functions there as
the first step. More methods will be moved to the module in the future.
The module is different from config.py because the latter only cares about
data structure and parsing, and does not care about special case, or system
config paths, or environment variables.
[1]: https://www.mercurial-scm.org/pipermail/mercurial-devel/2017-March/095503.html
Hardcoding 'more' -> 'more.com' means that 'more.exe' from MSYS would need to be
configured with its *.exe extension. This will resolve to either one, as
cmd.exe would have done if the command ran through the shell.
Something that's maybe problematic with this is it comes after 'pageractive' and
various ui configs have been set by the calling method. But the other early
exits in this method don't undo those changes either.
After 6a86fe38f1f6, with 'shell' being (mostly) set to False, invoking `more` no
longer worked. Instead, a warning was printed and the pager was disabled.
Invoking `more.com` works. Since a user may have configured 'pager.pager=more',
do this substitution at the end. Surprisingly, `more` does allow for arguments,
so those are preserved. This also allows `more` to work in MSYS.
Setting 'shell=False' runs the executable via CreateProcess(), which has rather
wonky rules for resolving an executable without an extension [1]. Resolving to
*.com is not among them. Since 'shell=True' yields a cryptic error for a bad
$PAGER, and a *.exe program will work without specifying the extension, sticking
with current 'shell=False' seems like the right thing to do. I don't think
there are any other *.com pagers out there, so this one special case seems OK.
If somebody wants to do something crazy that requires cmd.exe, I was able to get
normal paged output with 'pager.pager="cmd.exe /c more"'. I assume you can
replace `more` with *.bat, *.vbs or various other creatures listed in $PATHEXT.
[1] https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
We only have commands.{update,rebase}.requiredest so far. We should
clearly ignore those two if HGPLAIN is in effect, and it seems like we
should ignore any future config that will be added in [commands] since
that is about changing the behavior of commands.
Thanks to Yuya for suggesting to centralize the code in ui.py.
While at it, remove the unnecessary False values passed to
ui.configbool() for the aforementioned config options.
Long autogenerated blocked tags tend to be because the command has an absolute
path; at Facebook, we've had a few where the tag is thousands of characters
long (in association with the mergedriver).
Change the default to use a suffix of a command as the default tag, limiting us
to 85 characters (for a 100 character tag). This is long enough to overflow a
standard terminal (thus be obviously autogenerated), but short enough to be
readable.
I considered making this I/O be done in terms of bytes, but that would
cause an observable regression for Windows users, as non-binary-mode
open does EOL conversion there. There are probably new encoding
dragons lurking here, so we may want to switch to using binary mode
and doing EOL conversion ourselves.
The list parser is complex and reusable without ui. Let's move it to
config.py.
This allows us to parse a list from a "pure" config object without going
through ui. Like, we can make "_trustusers" calculated from raw configs,
instead of making sure it's synchronized by calling "fixconfig"s.
man(1) behaves as poorly as Mercurial without this change. This cribs
from git's run-command[0], which has a list of characters that imply a
string that needs to be run using 'sh -c'. If none of those characters
are present in the command string, we can use shell=False mode on
subprocess and get significantly better error messages (see the test)
when the pager process is invalid. With a complicated pager command
(that contains one of the unsafe characters), we behave as we do today
(which is no worse than git manages.)
I briefly tried tapdancing in a thread to catch early pager exits, but
it's just too perilous: you get races between fd duping operations and
a bad pager exiting, and it's too hard to differentiate between a
slow-bad-pager result and a fast-human-quit-pager-early result.
I've observed some weird variation in exit code handling in the "bad
experience" case in test-pager.t: on my Mac hg predictably exits
nonzero, but on Linux hg always exits zero in that case. For now,
we'll work around it with || true. :(
0: cddbda4bc8/run-command.c (L201)
Our source loader was errantly turning this --debugger into a bytes,
which was then causing me to still get a pager when I was using the
debugger on py3. That made life hard.
This is a step towards fixing extension load warnings on Python
3. Note that I suspect there are still some bugs in this area and that
things like color won't work, but the code at least executes and
prints text to the console correctly now.
Since we're working on bytestrings, we have to use [offset:offset+1]
to get consistent behavior on Python 2 and 3. I've only tested the
_parse_plain closure, not the _parse_quote one, but I have no real
reason to expect the latter to be broken since the fixes were fairly
mechanical.
Default-push has been deprecated in favour of default:pushurl. But "hg clone" still
inserts this in every hgrc file it creates. This patch updates the message by replacing
default-push with default:pushurl and also makes the necessary changes to test files.
Until callsites are updated, this will have no effect. Once callsites
are updated, specifying experimental.editortmpinhg will create editor
temporary files in a subdirectory of .hg, which will make it easier
for tool integrations to determine what repository is in play when
they're asked to edit an hg-related file.
Care needs to be taken to prevent leaking potentially sensitive environment
variables through hgweb, if template support for environment variables is to be
introduced. There are a few ideas about the API for preventing accidental
leaking [1]. Option 3 seems best from the POV of not needing to configure
anything in the normal case. I couldn't figure out how to do that, so guard it
with an experimental option for now.
[1] https://www.mercurial-scm.org/pipermail/mercurial-devel/2017-January/092383.html
readline() returns '' only when EOF is encountered, in which case, Python's
getpass() raises EOFError. We should do the same to abort the session as
"response expected."
This bug was reported to
https://bitbucket.org/tortoisehg/thg/issues/4659/
This dictionnary is affected by the content of the config, so we should have
one for each ui config.
We rename the global dict to '_baseterminfoparams' to make the situation
clearer.
Since a33895509ccb changed the signature of ui.system(), chgui.system()
should have been updated. This patch factors out the util.system() call
so that chg can override how a shell command is executed.
Before this changeset, the value was carried by the class to work around
limitation of the extensions initialisation. Now that the initialisation is
cleanly handled in 'dispatch', we can drop this work around.
This is similar to what we needed for 'write', we move the logic from the
extension to the core class. Beside the dispatch to 'win32print', we just apply
label to the argument.
That subcall to 'self.write' is never doing actual write but only store things
in buffers. So we do not need to protect it for exception not to time its
execution.
This will make it easier to extract a '_write_err' function as we did for
'write'.
One more step, the support for writing color is not directly in core. No
behavior change for the default case ('_colormode' = None).
Here are the details of what we have to change to the core method:
* apply to 'self.label' to input in the buffered case
* dispatch to 'win32print' when applicable
* apply to 'self.label' to input when applicable
We are about to add some extra logic related to color. That logic will need to
access the low level layer of ui doing the actual write to a stream. (eg:
'win32print'). We extract this logic into a private method for this purpose.
This bring us closer to supporting color in core natively. Core already have a
'label' method that was a no-op. We update its to call the new 'colorlabel'
function. Behavior is unchanged when colormode = None.
Having all 'ui' objects aware of 'color' allows us to update the core code to
handle color. The mode will stay 'None' in the default case so that will not
introduce any changes.