Commit Graph

551 Commits

Author SHA1 Message Date
Martin von Zweigbergk
979192be0c tweakdefaults: turn on ui.statuscopies
Seems obviously useful and probably off by default for historical
reasons.

Differential Revision: https://phab.mercurial-scm.org/D1444
2017-11-16 17:11:14 -08:00
Augie Fackler
ffa2157901 ui: add configlist doctest to document a bit more of the whitespace behavior
I'm surprised this wasn't explicitly tested, so I added a test.
2017-10-25 23:01:54 -04:00
Yuya Nishihara
21161a9bda configitems: relax warning about unwanted default value
The original condition was a bit harsh for extension authors since third-party
extensions need to preserve compatibility with older Mercurial versions, where
no defaults would be loaded from the configtable. So let's silence the warning
if the given default value matches, which should be harmless.
2017-10-31 22:37:30 +09:00
Saurabh Singh
8e631c99b7 ui: move request exit handlers to global state
Since the ui objects can be created with the 'load' class method, it
is possible to lose the exit handlers information from the old ui instance. For
example, running 'test-bad-extension.t' leads to this situation where chg
creates a new ui instance which does not copy the exit handlers from the
earlier ui instance. For exit handlers, which are special cases anyways, it
probably makes sense to have a global state of the handlers. This would ensure
that the exit handlers registered once are definitely executed at the end of
the request.

Test Plan:
Ran all the tests without '--chg' option. This also fixes the
'test-bad-extension.t' with the '--chg' option.

Differential Revision: https://phab.mercurial-scm.org/D1166
2017-10-17 13:20:25 -07:00
Boris Feld
38f9c73dbd configitems: adds a developer warning when accessing undeclared configuration
Now that all known options are declared, we setup a warning to make sure it will
stay this way.

We disable the warning in two tests checking other behavior with random options.
2017-10-16 17:41:27 +02:00
Boris Feld
142a0c0bf5 ui: add the possibility to returns None as username in ui
In a later patch we want to retrieve the current username or None if it isn't
defined. Add the acceptempty parameter instead of catching Abort.
2017-10-06 16:23:47 +02:00
Augie Fackler
83f88ecb85 tweakdefaults: make commands.update.check be noconflict
This is the second-safest option we have to offer in `updatecheck`,
with `abort` being the safest and `linear` being the default. At the
sprint we discussed how much `none` and `linear` make us all
uncomfortable, and how we'd like to move the default behavior if we can.

I'm not sure we can get away with actually changing the out of the box
default behavior, but we can at *least* do this.

Differential Revision: https://phab.mercurial-scm.org/D1062
2017-10-13 15:58:54 -04:00
Jun Wu
2ae56b14de codemod: use pycompat.iswindows
This is done by:

  sed -i "s/pycompat\.osname == 'nt'/pycompat.iswindows/" **/*.py
  sed -i "s/pycompat\.osname != 'nt'/not pycompat.iswindows/" **/*.py
  sed -i 's/pycompat.osname == "nt"/pycompat.iswindows/' **/*.py

Differential Revision: https://phab.mercurial-scm.org/D1034
2017-10-12 23:30:46 -07:00
Boris Feld
cfd170bf5c configitems: register the 'ui.interface.chunkselector' config 2017-10-11 05:36:10 +02:00
Augie Fackler
3835de40d8 ui: recommend tweakdefaults in the default hgrc template
Were I only slightly bolder, I'd make it on by default in the
suggested user hgrc.

Differential Revision: https://phab.mercurial-scm.org/D1001
2017-10-11 01:56:49 -07:00
Augie Fackler
ffcbb8d170 ui: convert to/from Optional[bytes] to Optional[str] in password manager
This password manager proxy is roughly the right-looking layer to
convert between strings and bytes. Many of these arguments can be
None, so we have a helper method to make the conversion preserve Nones
without exploding.

Differential Revision: https://phab.mercurial-scm.org/D886
2017-10-01 12:10:48 -04:00
Augie Fackler
c388df1839 httppasswordmgrdbproxy: specify exact arguments
We only ever call these functions in a single way, so let's just
actually specify them. We need to do some string/bytes encoding
dancing here for Python 3, so it'll help to know what arguments we
need to convert.

# no-check-commit because I'm modifying functions that check-commit
does not like.

Differential Revision: https://phab.mercurial-scm.org/D885
2017-10-01 07:29:51 -04:00
Martin von Zweigbergk
25360ba00c merge with stable 2017-09-30 07:52:48 -07:00
Mark Thomas
6fc38713f5 ui: check for progress singleton when clearing progress bar (issue5684)
A combination of wrapping `ui` and progress bars interrupted by exceptions can
lead to the progress bar not being cleared when the exception error is printed.
This results in corrupted-looking output like this:

```
updating [===============================>                        ] 1/2u
nresolved conflicts (see hg resolve, then hg rebase --continue)
```

This is because in `ui._progclear`, we only check the local reference to the
progress bar, not whether or not there is an instance of the singleton.  When a
progress bar is interrupted by an exception, the exception printing in
`scmutil.callcatch` uses the original instance of the `ui` object, not the
wrapped copy that has `_progbar` set.

When consider whether or not to clear the progress bar, check for the existence
of the singleton, rather than just whether or not we have a local reference to
it.

Differential Revision: https://phab.mercurial-scm.org/D743
2017-09-20 09:55:52 -07:00
Gregory Szorc
8e7a19b422 ui: restore behavior to ignore some I/O errors (issue5658)
45345e9870c3 and b30126fa95bc refactored ui methods to no longer
silently swallow some IOError instances. This is arguably the
correct thing to do. However, it had the unfortunate side-effect
of causing StdioError to bubble up to sensitive code like
transaction aborts, leading to an uncaught exceptions and failures
to e.g. roll back a transaction. This could occur when a remote
HTTP or SSH client connection dropped. The new behavior is
resulting in semi-frequent "abandonded transaction" errors on
multiple high-volume repositories at Mozilla.

This commit effectively reverts 45345e9870c3 and b30126fa95bc to
restore the old behavior.

I agree with the principle that I/O errors shouldn't be ignored.
That makes this change... unfortunate. However, our hands are tied
for what to do on stable. I think the proper solution is for the
ui's behavior to be configurable (possibly via a context manager).
During critical sections like transaction rollback and abort, it
should be possible to suppress errors. But this feature would not
be appropriate on stable.
2017-08-15 13:04:31 -07:00
Kostia Balytskyi
edfeaa5101 ui: make sure buffer is flushed before waiting for user input (issue5587)
Without this patch on Windows 'hg ci -i' hangs waiting for user input
and "examine changes to 'file'? [Ynesfdaq?]" is never displayed (at least
if the diff is sufficiently small). When Ctrl+C is pressed, this prompt
becomes visible, which suggests that the buffer just wasn't flushed.
I've never seen this happening on Linux, but this looks harmless enough
to not platform-gate it.
2017-08-05 13:19:09 -07:00
FUJIWARA Katsunori
af39ee1c25 ui: enable pager always for explicit --pager=on (issue5580)
Before this patch, explicit --pager=on is unintentionally ignored by
any disabling factor, even if priority of it is less than --pager=on
(e.g. "[ui] paginate = off").
2017-08-01 18:52:52 +09:00
Augie Fackler
4dfc9655ac ui: fix configbytes isinstance check to look for bytes and not str
Fixes configbytes on Python 3.
2017-07-24 13:50:25 -04:00
Jun Wu
e47f7dc2fa codemod: register core configitems using a script
This is done by a script [2] using RedBaron [1], a tool designed for doing
code refactoring. All "default" values are decided by the script and are
strongly consistent with the existing code.

There are 2 changes done manually to fix tests:

  [warn] mercurial/exchange.py: experimental.bundle2-output-capture: default needs manual removal
  [warn] mercurial/localrepo.py: experimental.hook-track-tags: default needs manual removal

Since RedBaron is not confident about how to indent things [2].

[1]: https://github.com/PyCQA/redbaron
[2]: https://github.com/PyCQA/redbaron/issues/100
[3]:

#!/usr/bin/env python
# codemod_configitems.py - codemod tool to fill configitems
#
# Copyright 2017 Facebook, Inc.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import, print_function

import os
import sys

import redbaron

def readpath(path):
    with open(path) as f:
        return f.read()

def writepath(path, content):
    with open(path, 'w') as f:
        f.write(content)

_configmethods = {'config', 'configbool', 'configint', 'configbytes',
                  'configlist', 'configdate'}

def extractstring(rnode):
    """get the string from a RedBaron string or call_argument node"""
    while rnode.type != 'string':
        rnode = rnode.value
    return rnode.value[1:-1]  # unquote, "'str'" -> "str"

def uiconfigitems(red):
    """match *.ui.config* pattern, yield (node, method, args, section, name)"""
    for node in red.find_all('atomtrailers'):
        entry = None
        try:
            obj = node[-3].value
            method = node[-2].value
            args = node[-1]
            section = args[0].value
            name = args[1].value
            if (obj in ('ui', 'self') and method in _configmethods
                and section.type == 'string' and name.type == 'string'):
                entry = (node, method, args, extractstring(section),
                         extractstring(name))
        except Exception:
            pass
        else:
            if entry:
                yield entry

def coreconfigitems(red):
    """match coreconfigitem(...) pattern, yield (node, args, section, name)"""
    for node in red.find_all('atomtrailers'):
        entry = None
        try:
            args = node[1]
            section = args[0].value
            name = args[1].value
            if (node[0].value == 'coreconfigitem' and section.type == 'string'
                and name.type == 'string'):
                entry = (node, args, extractstring(section),
                         extractstring(name))
        except Exception:
            pass
        else:
            if entry:
                yield entry

def registercoreconfig(cfgred, section, name, defaultrepr):
    """insert coreconfigitem to cfgred AST

    section and name are plain string, defaultrepr is a string
    """
    # find a place to insert the "coreconfigitem" item
    entries = list(coreconfigitems(cfgred))
    for node, args, nodesection, nodename in reversed(entries):
        if (nodesection, nodename) < (section, name):
            # insert after this entry
            node.insert_after(
                'coreconfigitem(%r, %r,\n'
                '    default=%s,\n'
                ')' % (section, name, defaultrepr))
            return

def main(argv):
    if not argv:
        print('Usage: codemod_configitems.py FILES\n'
              'For example, FILES could be "{hgext,mercurial}/*/**.py"')
    dirname = os.path.dirname
    reporoot = dirname(dirname(dirname(os.path.abspath(__file__))))

    # register configitems to this destination
    cfgpath = os.path.join(reporoot, 'mercurial', 'configitems.py')
    cfgred = redbaron.RedBaron(readpath(cfgpath))

    # state about what to do
    registered = set((s, n) for n, a, s, n in coreconfigitems(cfgred))
    toregister = {} # {(section, name): defaultrepr}
    coreconfigs = set() # {(section, name)}, whether it's used in core

    # first loop: scan all files before taking any action
    for i, path in enumerate(argv):
        print('(%d/%d) scanning %s' % (i + 1, len(argv), path))
        iscore = ('mercurial' in path) and ('hgext' not in path)
        red = redbaron.RedBaron(readpath(path))
        # find all repo.ui.config* and ui.config* calls, and collect their
        # section, name and default value information.
        for node, method, args, section, name in uiconfigitems(red):
            if section == 'web':
                # [web] section has some weirdness, ignore them for now
                continue
            defaultrepr = None
            key = (section, name)
            if len(args) == 2:
                if key in registered:
                    continue
                if method == 'configlist':
                    defaultrepr = 'list'
                elif method == 'configbool':
                    defaultrepr = 'False'
                else:
                    defaultrepr = 'None'
            elif len(args) >= 3 and (args[2].target is None or
                                     args[2].target.value == 'default'):
                # try to understand the "default" value
                dnode = args[2].value
                if dnode.type == 'name':
                    if dnode.value in {'None', 'True', 'False'}:
                        defaultrepr = dnode.value
                elif dnode.type == 'string':
                    defaultrepr = repr(dnode.value[1:-1])
                elif dnode.type in ('int', 'float'):
                    defaultrepr = dnode.value
            # inconsistent default
            if key in toregister and toregister[key] != defaultrepr:
                defaultrepr = None
            # interesting to rewrite
            if key not in registered:
                if defaultrepr is None:
                    print('[note] %s: %s.%s: unsupported default'
                          % (path, section, name))
                    registered.add(key) # skip checking it again
                else:
                    toregister[key] = defaultrepr
                    if iscore:
                        coreconfigs.add(key)

    # second loop: rewrite files given "toregister" result
    for path in argv:
        # reconstruct redbaron - trade CPU for memory
        red = redbaron.RedBaron(readpath(path))
        changed = False
        for node, method, args, section, name in uiconfigitems(red):
            key = (section, name)
            defaultrepr = toregister.get(key)
            if defaultrepr is None or key not in coreconfigs:
                continue
            if len(args) >= 3 and (args[2].target is None or
                                   args[2].target.value == 'default'):
                try:
                    del args[2]
                    changed = True
                except Exception:
                    # redbaron fails to do the rewrite due to indentation
                    # see https://github.com/PyCQA/redbaron/issues/100
                    print('[warn] %s: %s.%s: default needs manual removal'
                          % (path, section, name))
            if key not in registered:
                print('registering %s.%s' % (section, name))
                registercoreconfig(cfgred, section, name, defaultrepr)
                registered.add(key)
        if changed:
            print('updating %s' % path)
            writepath(path, red.dumps())

    if toregister:
        print('updating configitems.py')
        writepath(cfgpath, cfgred.dumps())

if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))
2017-07-14 14:22:40 -07:00
Boris Feld
40b893532b configitems: handle case were the default value is not static
In some case, the default of one value is derived from other value. We add a
way to register them anyway and an associated devel-warning.

The registration is very naive for the moment. We might be able to have a
better way for registering each of these cases but it could be done later.
2017-07-12 23:36:10 +02:00
David Demelier
d324b7a9bf configitems: add alias support in config
Aliases define optional alternatives to existing options. For example the old
option ui.user was deprecated and replaced by ui.username. With this mechanism,
it's even possible to create an alias to an option in a different section.

Add ui.user as alias to ui.username as an example of this concept.

The old alternates principle in ui.config is removed as it was used only for
this option.
2017-07-07 08:33:10 +02:00
Augie Fackler
6de511f29f ui: fix progress debug log format strings to work on Python 3 2017-09-18 13:37:00 -04:00
Yuya Nishihara
81c2aaf747 py3: convert function name to bytes in ui.configwith() 2017-09-03 17:47:21 +09:00
Yuya Nishihara
a71f259bd2 doctest: bulk-replace string literals with b'' for Python 3
Our code transformer can't rewrite string literals in docstrings, and I
don't want to make the transformer more complex.
2017-09-03 14:32:11 +09:00
Michael Bolin
16648b82d6 editor: file created for diff action should have .diff suffix
This is a follow-up to https://phab.mercurial-scm.org/D464 (02b917f3e672) that
introduced the new file extension behavior. It erroneously changed `.diff` to
`.diff.hg.txt`.

Test Plan:
Verified `make tests` passes, particularly `test-editor-filename.t`.

Differential Revision: https://phab.mercurial-scm.org/D607
2017-09-01 20:28:26 +00:00
Michael Bolin
094c271fff editor: use an unambiguous path suffix for editor files
Changes the API of `ui.edit()` to take an optional `action` argument,
which is used when constructing the suffix of the temp file.
Previously, it was possible to set the suffix by specifying a `suffix` to the
optional `extra` dict that was passed to `ui.edit()`, but the goal is to
drop support for `extra.suffix` and make `action` a required argument.
To this end, `ui.edit()` now yields a `develwarn()` if `action` is not set
or if `extra.suffix` is set.

I updated all calls to `ui.edit()` I could find in `hg-crew` to specify the
appropriate `action`. This means that when creating a commit, instead
of the path to the editor file being something like:

`/tmp/hg-editor-XXXXXX.txt`

it is now something like:

`/tmp/hg-editor-XXXXXX.commit.hg.txt`

Some editors (such as Atom) make it possible to statically define a [TextMate]
grammar for files with a particular suffix. For example, because Git reliably
uses `.git/COMMIT_EDITMSG` and `.git/MERGE_MSG` as the paths for commit-type
messages, it is trivial to define a grammar that is applied when files of
either name are opened in Atom:

https://github.com/atom/language-git/blob/v0.19.1/grammars/git%20commit%20message.cson#L4-L5

Because Hg historically used a generic `.txt` suffix, it was much harder to
disambiguate whether a file was an arbitrary text file as opposed to one
created for the specific purpose of authoring an Hg commit message.

This also makes it easier to add special support for `histedit`, as it has its own
suffix that is distinct from a commit:

`/tmp/hg-histedit-XXXXXX.histedit.hg.txt`

Test Plan:
Added an integration test: `test-editor-filename.t`.

Manually tested: ran `hg ci --amend` for this change and saw that it
used `/tmp/hg-editor-ZZjcz0.commit.hg.txt` as the path instead of
`/tmp/hg-editor-ZZjcz0.txt` as the path.

Verified `make tests` passes.

Differential Revision: https://phab.mercurial-scm.org/D464
2017-08-30 20:25:56 +00:00
Jun Wu
bd039f3688 pager: do not start pager if ui has been pushbuffer-ed
The `pushbuffer`, `popbuffer` APIs are intended to capture internal output.
They will prevent `ui.write` from writing to the actual `ui.fout`. So a
pager won't receive the output and do the right thing. In general, it does
not make sense to start a pager if ui is in the "pushbuffer" mode.

Differential Revision: https://phab.mercurial-scm.org/D574
2017-08-30 14:04:55 -07:00
Sean Farley
e18a90ab08 merge with stable 2017-08-21 21:35:06 -07:00
Augie Fackler
a80f148d0c py3: introduce a wrapper for __builtins__.{raw_,}input()
In order to make this work, we have to wrap the io streams in a
TextIOWrapper so that __builtins__.input() can do unicode IO on Python
3. We can't just restore the original (unicode) sys.std* because we
might be running a cmdserver, and if we blindly restore sys.* to the
original values then we end up breaking the cmdserver. Sadly,
TextIOWrapper tries to close the underlying stream during its __del__,
so we have to make a sublcass to prevent that.

If you see errors like:

TypeError: a bytes-like object is required, not 'str'

On an input() or print() call on Python 3, the substitution of
sys.std* is probably the root cause.

A previous version of this change tried to put the bytesinput() method
in pycompat - it turns out we need to do some encoding handling, so we
have to be in a higher layer that's allowed to use
mercurial.encoding.encoding. As a result, this is in util for now,
with the TextIOWrapper subclass hiding in encoding.py. I'm not sure of
a better place for the time being.

Differential Revision: https://phab.mercurial-scm.org/D299
2017-07-24 14:38:40 -04:00
Augie Fackler
9a0febea27 merge with stable 2017-08-10 14:23:41 -04:00
Augie Fackler
dadffe35c4 ui: refactor extractchoices so it doesn't break on Python 3
Differential Revision: https://phab.mercurial-scm.org/D275
2017-07-24 13:48:32 -04:00
Yuya Nishihara
126b1dc317 py3: use bytes IO to write sample hgrc
Unicode sucks. Stop using Text IO and manually convert line endings.
2017-08-03 00:45:02 +09:00
Pierre-Yves David
8eb6764bad configitems: support callable as a default value
Yuya pointed out that using mutable value as the default could be problematic.
To work around this we now support callable object as default value. This
allows for creating new mutable objects on demand when needed.
2017-06-28 13:50:20 +02:00
Pulkit Goyal
d7e69a39e2 py3: add b'' to make the regex pattern bytes 2017-06-25 03:11:55 +05:30
Pierre-Yves David
e2366ea12d configitems: register 'ui.interactive'
That item default value is a bit special (None) so this adds a second proof
that everything is still working fine.
2017-06-23 17:19:29 +02:00
Pierre-Yves David
337073fb57 config: use '_config' within 'configbytes'
This will prevent bugs from using None as the sentinel value (eg:
'ui.interactive')
2017-06-25 14:41:12 +02:00
Pierre-Yves David
bcbc568807 config: use '_config' within 'configbool'
This will prevent bugs from using None as the sentinel value (eg:
'ui.interactive')
2017-06-25 14:38:56 +02:00
Pierre-Yves David
634a0d74db config: extract the core config logic into a private method
This will make it easier for the other 'configxxx' function to detect unset
value.
2017-06-25 14:34:34 +02:00
Pierre-Yves David
4579a8de56 configitems: issue a devel warning when overriding default config
If the option is registered, there is already a default value available and
passing a new one is at best redundant. So we issue a deprecation warning in
this case.

(note: there will be case were the default value will not be as simple as what
is currently possible. We'll upgrade the configitems code to handle them in
time.)
2017-06-17 13:08:03 +02:00
Pierre-Yves David
7918debc04 configitems: get default values from the central registry when available
We do not have any registered config yet, but we are now ready to use them.

For now we ignore this feature for config access with "alternates". On the long
run, we expect alternates to be handled as "aliases" by the config item
themself.
2017-06-17 12:15:28 +02:00
Pierre-Yves David
ba2fa929d4 configitems: introduce a central registry for config option
We now have the appropriate infrastructure to register config items. Usage will
added in the next changeset.
2017-06-17 18:43:27 +02:00
Pierre-Yves David
5640bb2ad1 config: use the new '_unset' value for 'configsuboptions'
This should let configsuboptions delegate all special processing of the default
config value to the main 'config' method.
2017-06-17 12:51:37 +02:00
Pierre-Yves David
3828008441 config: use the 'config' method in 'configsuboptions'
There was unnecessary code duplication. It was getting in the way of the
unification of the default value logic.
2017-06-17 18:28:20 +02:00
Pierre-Yves David
30b883a533 config: use the new '_unset' value for 'configpath'
This should let 'configpath' delegate all special processing of the default
config value to the main 'config' method.
2017-06-17 12:52:02 +02:00
Pierre-Yves David
73fc40fe02 config: use the new '_unset' value for 'configdate'
This should let 'configdate' delegate all special processing of the default
config value to the main 'config' method.

The default value for date (None) is still enforced in this method if no other
default were passed.
2017-06-17 12:54:45 +02:00
Pierre-Yves David
3ba5dde647 config: use the new '_unset' value for 'configlist'
This should let 'configlist' delegate all special processing of the default
config value to the main 'config' method.

The default config value ([]) is still handled in this method.
2017-06-17 12:54:04 +02:00
Pierre-Yves David
dd12eb0ca1 config: use the new '_unset' value for 'configbytes'
This should let 'configbytes' delegates all special processing of the default
config value to the main 'config' method.
2017-06-17 12:53:51 +02:00
Pierre-Yves David
a1226e02b2 config: use the new '_unset' value for 'configint'
This should let 'configint' delegates all special processing of the default
config value to the main 'config' method.
2017-06-17 12:53:40 +02:00
Pierre-Yves David
488077019c config: use the new '_unset' value for 'configwith'
This should let 'configwith' delegate all special processing of the default
config value to the main 'config' method.

This changeset introduce a small change in behavior since the default value is
run through the 'convert' function. This does not seems harmful and no actual
test break. This small change make the code simpler so I'm keeping it.
2017-06-17 12:52:31 +02:00
Pierre-Yves David
ae76544acb config: use the new '_unset' value for 'configbool'
This should let 'configbool' delegate all special processing of the default
config value to the main 'config' method.

The default value for bool (False) is still enforced in this method if no other
default were passed.
2017-06-17 12:52:16 +02:00