##// END OF EJS Templates
match: add `filepath:` pattern to match an exact filepath relative to the root...
match: add `filepath:` pattern to match an exact filepath relative to the root It's useful in certain automated workflows to make sure we recurse in directories whose name conflicts with files in other revisions. In addition it makes it possible to avoid building a potentially costly regex, improving performance when the set of files to match explicitly is large. The benchmark below are run in the following configuration : # data-env-vars.name = mozilla-central-2018-08-01-zstd-sparse-revlog # benchmark.name = files # benchmark.variants.rev = tip # benchmark.variants.files = all-list-filepath-sorted # bin-env-vars.hg.flavor = no-rust It also includes timings using the re2 engine (through the `google-re2` module) to show how much can be saved by just using a better regexp engine. Pattern time (seconds) time using re2 ----------------------------------------------------------- just "." 0.4 0.4 list of "filepath:…" 1.3 1.3 list of "path:…" 25.7 3.9 list of patterns 29.7 10.4 As you can see, Without re2, using "filepath:" instead of "path:" is a huge win. With re2, it is still about three times faster to not have to build the regex.

File last commit:

r49768:f254fc73 default
r51588:1c31b343 default
Show More
similar.py
131 lines | 3.9 KiB | text/x-python | PythonLexer
David Greenaway
Move 'findrenames' code into its own file....
r11059 # similar.py - mechanisms for finding similar files
#
Raphaël Gomès
contributor: change mentions of mpm to olivia...
r47575 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
David Greenaway
Move 'findrenames' code into its own file....
r11059 #
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Gregory Szorc
similar: use absolute_import
r27359
from .i18n import _
Gregory Szorc
py3: finish porting iteritems() to pycompat and remove source transformer...
r43376 from . import (
mdiff,
)
Augie Fackler
formatting: blacken the codebase...
r43346
David Greenaway
Move 'findrenames' code into its own file....
r11059
David Greenaway
findrenames: Optimise "addremove -s100" by matching files by their SHA1 hashes....
r11060 def _findexactmatches(repo, added, removed):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """find renamed files that have no changes
David Greenaway
findrenames: Optimise "addremove -s100" by matching files by their SHA1 hashes....
r11060
Takes a list of new filectxs and a list of removed filectxs, and yields
(before, after) tuples of exact matches.
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """
Yuya Nishihara
similar: use cheaper hash() function to test exact matches...
r31584 # Build table of removed files: {hash(fctx.data()): [fctx, ...]}.
# We use hash() to discard fctx.data() from memory.
David Greenaway
findrenames: Optimise "addremove -s100" by matching files by their SHA1 hashes....
r11060 hashes = {}
Augie Fackler
formatting: blacken the codebase...
r43346 progress = repo.ui.makeprogress(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'searching for exact renames'),
Augie Fackler
formatting: blacken the codebase...
r43346 total=(len(added) + len(removed)),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 unit=_(b'files'),
Augie Fackler
formatting: blacken the codebase...
r43346 )
Martin von Zweigbergk
similar: use progress helper...
r38367 for fctx in removed:
progress.increment()
Yuya Nishihara
similar: use cheaper hash() function to test exact matches...
r31584 h = hash(fctx.data())
if h not in hashes:
hashes[h] = [fctx]
else:
hashes[h].append(fctx)
David Greenaway
findrenames: Optimise "addremove -s100" by matching files by their SHA1 hashes....
r11060
# For each added file, see if it corresponds to a removed file.
Martin von Zweigbergk
similar: use progress helper...
r38367 for fctx in added:
progress.increment()
FUJIWARA Katsunori
similar: compare between actual file contents for exact identity...
r31210 adata = fctx.data()
Yuya Nishihara
similar: use cheaper hash() function to test exact matches...
r31584 h = hash(adata)
for rfctx in hashes.get(h, []):
FUJIWARA Katsunori
similar: compare between actual file contents for exact identity...
r31210 # compare between actual file contents for exact identity
if adata == rfctx.data():
yield (rfctx, fctx)
Yuya Nishihara
similar: use cheaper hash() function to test exact matches...
r31584 break
David Greenaway
findrenames: Optimise "addremove -s100" by matching files by their SHA1 hashes....
r11060
# Done
Martin von Zweigbergk
progress: hide update(None) in a new complete() method...
r38392 progress.complete()
David Greenaway
findrenames: Optimise "addremove -s100" by matching files by their SHA1 hashes....
r11060
Augie Fackler
formatting: blacken the codebase...
r43346
Sean Farley
similar: move score function to module level...
r30805 def _ctxdata(fctx):
# lazily load text
orig = fctx.data()
return orig, mdiff.splitnewlines(orig)
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
similar: remove caching from the module level...
r30809 def _score(fctx, otherdata):
orig, lines = otherdata
text = fctx.data()
Yuya Nishihara
bdiff: proxy through mdiff module...
r32201 # mdiff.blocks() returns blocks of matching lines
Sean Farley
similar: move score function to module level...
r30805 # count the number of bytes in each
equal = 0
Yuya Nishihara
bdiff: proxy through mdiff module...
r32201 matches = mdiff.blocks(text, orig)
Sean Farley
similar: move score function to module level...
r30805 for x1, x2, y1, y2 in matches:
for line in lines[y1:y2]:
equal += len(line)
lengths = len(text) + len(orig)
return equal * 2.0 / lengths
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
similar: remove caching from the module level...
r30809 def score(fctx1, fctx2):
return _score(fctx1, _ctxdata(fctx2))
Augie Fackler
formatting: blacken the codebase...
r43346
David Greenaway
findrenames: Optimise "addremove -s100" by matching files by their SHA1 hashes....
r11060 def _findsimilarmatches(repo, added, removed, threshold):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """find potentially renamed files based on similar file content
David Greenaway
findrenames: Optimise "addremove -s100" by matching files by their SHA1 hashes....
r11060
Takes a list of new filectxs and a list of removed filectxs, and yields
(before, after, score) tuples of partial matches.
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """
David Greenaway
Move 'findrenames' code into its own file....
r11059 copies = {}
Augie Fackler
formatting: blacken the codebase...
r43346 progress = repo.ui.makeprogress(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'searching for similar files'), unit=_(b'files'), total=len(removed)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Martin von Zweigbergk
similar: use progress helper...
r38414 for r in removed:
progress.increment()
Pierre-Yves David
similar: remove caching from the module level...
r30809 data = None
David Greenaway
Move 'findrenames' code into its own file....
r11059 for a in added:
bestscore = copies.get(a, (None, threshold))[1]
Pierre-Yves David
similar: remove caching from the module level...
r30809 if data is None:
data = _ctxdata(r)
myscore = _score(a, data)
Yuya Nishihara
similar: take the first match instead of the last...
r31583 if myscore > bestscore:
David Greenaway
Move 'findrenames' code into its own file....
r11059 copies[a] = (r, myscore)
Martin von Zweigbergk
similar: use progress helper...
r38414 progress.complete()
David Greenaway
Move 'findrenames' code into its own file....
r11059
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for dest, v in copies.items():
Sean Farley
similar: rename local variable to not collide with previous...
r30791 source, bscore = v
yield source, dest, bscore
David Greenaway
Move 'findrenames' code into its own file....
r11059
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
similar: do not look up and create filectx more than once...
r31582 def _dropempty(fctxs):
return [x for x in fctxs if x.size() > 0]
Augie Fackler
formatting: blacken the codebase...
r43346
David Greenaway
findrenames: Optimise "addremove -s100" by matching files by their SHA1 hashes....
r11060 def findrenames(repo, added, removed, threshold):
'''find renamed files -- yields (before, after, score) tuples'''
Yuya Nishihara
similar: use common names for changectx variables...
r31581 wctx = repo[None]
pctx = wctx.p1()
David Greenaway
Move 'findrenames' code into its own file....
r11059
David Greenaway
findrenames: Optimise "addremove -s100" by matching files by their SHA1 hashes....
r11060 # Zero length files will be frequently unrelated to each other, and
# tracking the deletion/addition of such a file will probably cause more
# harm than good. We strip them out here to avoid matching them later on.
Yuya Nishihara
similar: do not look up and create filectx more than once...
r31582 addedfiles = _dropempty(wctx[fp] for fp in sorted(added))
removedfiles = _dropempty(pctx[fp] for fp in sorted(removed) if fp in pctx)
David Greenaway
findrenames: Optimise "addremove -s100" by matching files by their SHA1 hashes....
r11060
# Find exact matches.
Yuya Nishihara
similar: get rid of quadratic addedfiles.remove()...
r31580 matchedfiles = set()
for (a, b) in _findexactmatches(repo, addedfiles, removedfiles):
matchedfiles.add(b)
David Greenaway
findrenames: Optimise "addremove -s100" by matching files by their SHA1 hashes....
r11060 yield (a.path(), b.path(), 1.0)
# If the user requested similar files to be matched, search for them also.
if threshold < 1.0:
Yuya Nishihara
similar: get rid of quadratic addedfiles.remove()...
r31580 addedfiles = [x for x in addedfiles if x not in matchedfiles]
Augie Fackler
formatting: blacken the codebase...
r43346 for (a, b, score) in _findsimilarmatches(
repo, addedfiles, removedfiles, threshold
):
David Greenaway
findrenames: Optimise "addremove -s100" by matching files by their SHA1 hashes....
r11060 yield (a.path(), b.path(), score)