Commit Graph

777 Commits

Author SHA1 Message Date
Matt Harbison
44fdb73d25 context: name files relative to cwd in warning messages
I was several directories deep in the kernel tree, ran `hg add`, and got the
warning about the size of one of the files.  I noticed that it suggested undoing
the add with a specific revert command.  The problem is, it would have failed
since the path printed was relative to the repo root instead of cwd.  While
here, I just fixed the other messages too.  As an added benefit, these messages
now look the same as the verbose/inexact messages for the corresponding command.

I don't think most of these messages are reachable (typically the corresponding
cmdutil function does the check).  I wasn't able to figure out why the keyword
tests were failing when using pathto()- I couldn't cause an absolute path to be
used by manipulating the --cwd flag on a regular add.  (I did notice that
keyword is adding the file without holding wlock.)
2017-07-11 00:40:29 -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
Matt Harbison
557dc0142f subrepo: consider the parent repo dirty when a file is missing
This simply passes the 'missing' argument down from the context of the parent
repo, so the same rules apply.  subrepo.bailifchanged() is hardcoded to care
about missing files, because cmdutil.bailifchanged() is too.

In the end, it looks like this addresses inconsistencies with 'archive',
'identify', blackbox logs, 'merge', and 'update --check'.  I wasn't sure how to
implement this in git, so that's left for someone more familiar with it.
2017-07-09 02:55:46 -04:00
Gregory Szorc
2689134340 sparse: move post commit actions into core
Instead of wrapping committablectx.markcommitted(), we inline
the call into workingctx.markcommitted().

Per smf's review, workingctx is the proper location for this
code, as committablectx is the shared base class for it and
memctx. Since this code touches the working directory, it belongs
in workingctx.
2017-07-07 11:51:10 -07:00
Phil Cohen
a65f43e3e4 workingfilectx: add exists, lexists
Switch the lone call in merge.py to use it.

As with past refactors, the goal is to make wctx hot-swappable with an
in-memory context in the future. This change should be a no-op today.
2017-07-04 22:35:52 -07:00
Phil Cohen
22861c5e86 workingfilectx: add audit() as a wrapper for wvfs.audit() 2017-06-25 22:30:14 -07:00
Phil Cohen
8b63d9e6f0 workingfilectx: add backgroundclose as a kwarg to write()
This is necessary because some callers in merge.py pass backgroundclose=True
when writing.

As with previous changes in this series, this should be a no-op.
2017-06-25 22:30:14 -07:00
Phil Cohen
67430178c3 merge: change repo.wvfs.setflags calls to a new wctx[f].setflags function
As with previous changes in this series, this should be a no-op.
2017-06-25 22:29:09 -07:00
Yuya Nishihara
0c45446525 py3: add utility to forward __str__() to __bytes__()
It calls unifromlocal() instead of sysstr() because __bytes__() may contain
locale-dependent values such as paths.
2017-06-24 13:48:04 +09:00
Pulkit Goyal
078a0909bb py3: define __bytes__ for basefilectx class
The implementation is shamely copied from the __str__ function
2017-06-22 03:22:30 +05:30
Yuya Nishihara
e75a42ecc9 dagop: move blockancestors() and blockdescendants() from context
context.py seems not a good place to host these functions.

  % wc -l mercurial/context.py mercurial/dagop.py
    2306 mercurial/context.py
     424 mercurial/dagop.py
    2730 total
2017-02-19 19:37:14 +09:00
Siddharth Agarwal
f23bf55820 workingctx: add a way for extensions to run code at status fixup time
Some extensions like fsmonitor need to run code after dirstate.status is
called, but while the wlock is held. The extensions could grab the wlock again,
but that has its own peculiar race issues. For example, fsmonitor would not
like its state to be written out if the dirstate has changed underneath (see
issue5581 for what can go wrong in that sort of case).

To protect against these sorts of issues, allow extensions to declare that they
would like to run some code to run at fixup time.

fsmonitor will switch to using this in the next patch in the series.
2017-06-12 13:56:50 -07:00
Siddharth Agarwal
a6ba4f248d workingctx: also pass status tuple into poststatusfixup
fsmonitor is going to need this to compute its set of notable files to persist.
2017-06-12 13:56:43 -07:00
Siddharth Agarwal
05506e53ba workingctx: factor out post-status dirstate fixup
We want to allow extensions to be able to add code to run inside the wlock.
2017-06-12 13:54:59 -07:00
Sean Farley
e7d53c6c2e memctx: always use cache for filectxfn
I don't see a downside to doing this unless I'm missing something.
Thanks to foozy for correcting my previous bad logic.
2017-06-10 16:00:18 -07:00
Sean Farley
1221c3301c context: inline makememctx (API)
I have always thought it weird that we have a helper method instead of
just using __init__. So, I ripped it out.
2017-06-10 10:24:33 -04:00
Sean Farley
e67eb8ee09 context: add convenience method for returning a memfilectx from a patch
This is mostly a copy of what makememctx does but refactored to make it
behave more like our other convenience methods.
2017-06-09 13:39:13 -07:00
Sean Farley
90b054fc18 memctx: refactor inline getfilectx into convenience method
No actual logic is changing, just moving code so __init__ is easier to
read.
2017-06-09 13:25:02 -07:00
FUJIWARA Katsunori
457ca6840f context: avoid writing outdated dirstate out (issue5584)
Before this patch, workingctx.status() may cause writing outdated
dirstate out, if:

  - .hg/dirstate is changed simultaneously after last loading it,
  - there is any file, which should be dirstate.normal()-ed

Typical issue case is:

  - the working directory is updated by "hg update"
  - .hg/dirstate is updated in background (e.g. fsmonitor)

This patch compares identities of dirstate before and after
acquisition of wlock, and avoids writing outdated dirstate out, if
change of .hg/dirstate is detected.
2017-06-09 13:07:49 +09:00
Martin von Zweigbergk
a9c40085c0 match: allow pats to be None
match.match already interprets "!bool(patterns)" as matching
everything (but includes and excludes still apply). We might as well
allow None, which lets us simplify some callers a bit.

I originally wrote this patch while trying to change
match.match(patterns=[]) to mean to match no patterns. This patch is
one step towards that goal. I'm not sure it'll be worth the effort to
go all the way there, but I think this patch still makes sense on its
own.
2017-06-08 22:18:17 -07:00
Yuya Nishihara
e6297851af localrepo: map integer and hex wdir identifiers to workingctx
changectx.__init__() is slightly modified to take str(wdirrev) as a valid
integer revision (and raise WdirUnsupported exception.)

Test will be added by the next patch.
2016-08-19 18:40:35 +09:00
Augie Fackler
9a722d4382 merge with stable 2017-06-03 16:33:28 -04:00
Siddharth Agarwal
41dae969eb status: don't crash if a lookup file disappears
This can happen if another process (even another hg process!) comes along and
removes the file at that time.

This partly resolves issue5584, but not completely -- a bogus dirstate update
can still happen. However, the full fix is too involved for stable.
2017-06-02 22:27:52 -07:00
Pulkit Goyal
4dc6c9b676 py3: implement __bytes__ for committablectx
Before this method, calling bytes on workingctx or memctx calls
basectx.__bytes__ since the magic method was not defined for this class. When it
calls the method from basectx class, it returns TypeError because None is passed
into it.

After this commit `hg update -C` works on Python 3 if eol is not enabled.
2017-06-01 02:25:18 +05:30
Denis Laxalde
d7d47fec65 context: optimize linkrev adjustment in blockancestors() (issue5538)
We set parent._descendantrev = child.rev() when walking parents in
blockancestors() so that, when linkrev adjustment is perform for these, it
starts from a close descendant instead of possibly topmost introrev. (See
`self._adjustlinkrev(self._descendantrev)` in filectx._changeid().)

This is similar to changeset 8758896efb1c, which added a "f._changeid"
instruction in annotate() for the same purpose.
However, here, we set _descendantrev explicitly instead of relying on the
'_changeid' cached property being accessed (with effect to set _changeid
attribute) so that, in _parentfilectx() (called from parents()), we go through
`if '_changeid' in vars(self) [...]` branch in which instruction
`fctx._descendantrev = self.rev()` finally appears and does what we want.

With this, we can roughly get a 3x speedup (including in example of issue5538
from mozilla-central repository) on usage of followlines revset (and
equivalent hgweb request).
2017-04-24 18:33:23 +02:00
Denis Laxalde
7cc06d2fbf context: start walking from "introrev" in blockancestors()
Previously, calling blockancestors() with a fctx not touching file would
sometimes yield this filectx first, instead of the first "block ancestor",
because when compared to its parent it may have changes in specified line
range despite not touching the file at all.

Fixing this by starting the algorithm from the "base" filectx obtained using
fctx.introrev() (as done in annotate()).

In tests, add a changeset not touching file we want to follow lines of to
cover this case. Do this in test-annotate.t for followlines revset tests and
in test-hgweb-filelog.t for /log/<rev>/<file>?linerange=<from>:<to> tests.
2017-04-20 21:40:28 +02:00
Pierre-Yves David
d03144db9c hidden: extract the code generating "filtered rev" error for wrapping
The goal is to help experimentation in extensions (ie: evolve) around more
advance messages.
2017-04-15 18:13:10 +02:00
Denis Laxalde
631e6988ca context: possibly yield initial fctx in blockdescendants()
If initial 'fctx' has changes in line range with respect to its parents, we
yield it first. This makes 'followlines(..., descend=True)' consistent with
'descendants()' revset which yields the starting revision.

We reuse one iteration of blockancestors() which does exactly what we want.

In test-annotate.t, adjust 'startrev' in one case to cover the situation where
the starting revision does not touch specified line range.
2017-04-14 14:25:06 +02:00
Denis Laxalde
559326afdb context: add an assertion checking linerange consistency in blockdescendants()
If this assertion fails, this indicates a flaw in the algorithm. So fail fast
instead of possibly producing wrong results.

Also extend the target line range in test to catch a merge changeset with all
its parents.
2017-04-14 14:09:26 +02:00
Denis Laxalde
761577866a context: follow all branches in blockdescendants()
In the initial implementation of blockdescendants (and thus followlines(...,
descend=True) revset), only the first branch encountered in descending
direction was followed.

Update the algorithm so that all children of a revision ('x' in code) are
considered. Accordingly, we need to prevent a child revision to be yielded
multiple times when it gets visited through different path, so we skip 'i'
when this occurs. Finally, since we now consider all parents of a possible
child touching a given line range, we take care of yielding the child if it
has a diff in specified line range with at least one of its parent (same logic
as blockancestors()).
2017-04-14 08:55:18 +02:00
Pulkit Goyal
9d6a7aa555 py3: make sure we return strings from __str__ and __repr__
On Python 3:

>>> class abc:
...     def __repr__(self):
...             return b'abc'
...
>>> abc()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __repr__ returned non-string (type bytes)

>>> class abc:
...     def __str__(self):
...             return b'abc'
...
>>> str(abc())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __str__ returned non-string (type bytes)

So the __str__ and __repr__ must return strings.
2017-06-01 00:00:10 +05:30
Sean Farley
e94da1f6fd context: move dirty() to committablectx
This is a pedantic move. It should be an error if dirty() is called on a
read-only context. Based on Mads Kiilerix's and my work at the sprint.
2017-05-11 13:59:48 -07:00
Sean Farley
4eadbcd953 committablectx: extra is already normalized by committablectx.__init__
Avoid doing the same work again. Based on work done by Mads Kiilerix.
2017-05-11 13:51:10 -07:00
Denis Laxalde
d7409a0458 context: add a blockdescendants function
This is symmetrical with blockancestors() and yields descendants of a filectx
with changes in the given line range. The noticeable difference is that the
algorithm does not follow renames (probably because filelog.descendants() does
not), so we are missing branches with renames.
2017-04-10 15:11:36 +02:00
Jun Wu
e06554212d metadataonlyctx: replace "changeset()[0]" to "manifestnode()"
As Yuya pointed out [1], "changeset()[0]" could be simplified to
"manifestnode()". I didn't notice that method earlier. It should definitely
be used - it's easier to read, and faster.

[1]: https://www.mercurial-scm.org/pipermail/mercurial-devel/2017-March/095716.html
2017-04-07 11:02:43 -07:00
Jun Wu
faefa92b13 metadataonlyctx: speed up sanity check
Previously the sanity check will construct manifestctx for both p1 and p2.
But it only needs the "manifest node" information, which could be read from
changelog directly.
2017-03-26 12:26:35 -07:00
FUJIWARA Katsunori
aaa8db9cef misc: update descriptions about removed file for filectxfn
Since 2eef89bfd70d, filectxfn for memctx should return None for
removed file instead of raising IOError.
2017-03-24 22:13:23 +09:00
Gregory Szorc
5ca0f908bf py3: add __bool__ to every class defining __nonzero__
__nonzero__ was renamed to __bool__ in Python 3. This patch simply
aliases __bool__ to __nonzero__ for every class implementing
__nonzero__.
2017-03-13 12:40:14 -07:00
Pierre-Yves David
8561a8e8ff context: simplify call to icase matcher in 'match()'
The two function takes the very same arguments. We make this clearer and less
error prone by dispatching on the function only and having a single call point
in the code.
2017-03-15 15:38:02 -07:00
Pierre-Yves David
b9d210d680 context: explicitly tests for None
Changeset c832083e5671 removed the mutable default value, but did not explicitly
tested for None. Such implicit testing can introduce semantic and performance
issue. We move to an explicit testing for None as recommended by PEP8:

https://www.python.org/dev/peps/pep-0008/#programming-recommendations
2017-03-15 15:33:24 -07:00
Gregory Szorc
b1f8fb51cd context: don't use mutable default argument value
Mutable default argument values are a Python gotcha and can
represent subtle, hard-to-find bugs. Lets rid our code base
of them.
2017-03-12 21:50:42 -07:00
Augie Fackler
d214daa434 context: use portable construction to verify int parsing 2017-03-12 00:43:47 -05:00
Augie Fackler
d44c41fe19 context: implement both __bytes__ and __str__ for Python 3
They're very similar, for obvious reasons.
2017-03-11 20:57:40 -05:00
Augie Fackler
89600a72c4 context: work around long not existing on Python 3
I can't figure out what this branch is even trying to accomplish, and
it was introduced in 387a3aa50d61 which doesn't really shed any
insight into why longs are treated differently from ints.
2017-03-11 20:57:04 -05:00
Jun Wu
f7e72658ec context: do not cache manifestctx
This will make sure when ctx.repo.manifestlog changes, a correct new
manifestctx is returned. repo.manifestlog takes care of caching so the
manifestctx won't be reconstructed every time.
2017-05-25 17:20:43 -07:00
Siddharth Agarwal
51c7d417b5 annotate: add a new experimental --skip option to skip revs
This option is most useful for mechanical code modifications, especially ones
that retain the same number of lines.
2017-05-24 19:39:33 -07:00
Siddharth Agarwal
259f128038 annotate: add core algorithm to skip a rev
The core algorithm is inspired by git hyper-blame, implemented at
https://chromium.googlesource.com/chromium/tools/depot_tools.git/+/master/git_hyper_blame.py.

The heuristic is as documented in the comments.
2017-05-24 19:07:14 -07:00
Siddharth Agarwal
19daf128b1 annotate: make pair take all parents to pair against
In upcoming patches we'll need to be aware of all parents at the same time.

This also exposes a potential bug: if a line can be annotated with both parents
of a merge commit, it'll always be annotated with p2, not p1. I'm not sure if
that's what we want, but at least the code makes it clear now.
2017-05-24 17:40:08 -07:00
Siddharth Agarwal
136c8f6192 annotate: move pair function to top level
We'll want to make this more complicated and have unit tests for it in upcoming
patches.
2017-05-24 17:38:28 -07:00
Boris Feld
b66380af61 devel: add a config field to force dates to timestamp 0
Add a new config field named default-date under the devel section to force all
implicits date to a specific value. If a explicit date is passed, it will
override the default.

This patch only affect changesets. Other usages (blackbox, obsmarkers) are
updated in later patchs.

The test runner is setting a bunch of alias to force the '--date' argument. We
will replace theses aliases in a later patch.
2017-05-19 12:18:25 +02:00