##// END OF EJS Templates
automv: switch to specifying the similarity as an integer (0-100)...
Martijn Pieters -
r28152:5ec1ce8f default
parent child Browse files
Show More
@@ -1,85 +1,87 b''
1 1 # automv.py
2 2 #
3 3 # Copyright 2013-2016 Facebook, Inc.
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7 """Check for unrecorded moves at commit time (EXPERIMENTAL)
8 8
9 9 This extension checks at commit/amend time if any of the committed files
10 10 comes from an unrecorded mv.
11 11
12 12 The threshold at which a file is considered a move can be set with the
13 ``automv.similarity`` config option; the default value is 1.00.
13 ``automv.similarity`` config option. This option takes a percentage between 0
14 (disabled) and 100 (files must be identical), the default is 100.
14 15
15 16 """
16 17 from __future__ import absolute_import
17 18
18 19 from mercurial import (
19 20 commands,
20 21 copies,
21 22 extensions,
22 23 scmutil,
23 24 similar
24 25 )
25 26 from mercurial.i18n import _
26 27
27 28 def extsetup(ui):
28 29 entry = extensions.wrapcommand(
29 30 commands.table, 'commit', mvcheck)
30 31 entry[1].append(
31 32 ('', 'no-automv', None,
32 33 _('disable automatic file move detection')))
33 34
34 35 def mvcheck(orig, ui, repo, *pats, **opts):
35 36 """Hook to check for moves at commit time"""
36 37 renames = None
37 38 disabled = opts.pop('no_automv', False)
38 39 if not disabled:
39 threshold = float(ui.config('automv', 'similarity', '1.00'))
40 threshold = float(ui.config('automv', 'similarity', '100'))
40 41 if threshold > 0:
41 42 match = scmutil.match(repo[None], pats, opts)
42 43 added, removed = _interestingfiles(repo, match)
43 renames = _findrenames(repo, match, added, removed, threshold)
44 renames = _findrenames(repo, match, added, removed,
45 threshold / 100.0)
44 46
45 47 with repo.wlock():
46 48 if renames is not None:
47 49 scmutil._markchanges(repo, (), (), renames)
48 50 return orig(ui, repo, *pats, **opts)
49 51
50 52 def _interestingfiles(repo, matcher):
51 53 """Find what files were added or removed in this commit.
52 54
53 55 Returns a tuple of two lists: (added, removed). Only files not *already*
54 56 marked as moved are included in the added list.
55 57
56 58 """
57 59 stat = repo.status(match=matcher)
58 60 added = stat[1]
59 61 removed = stat[2]
60 62
61 63 copy = copies._forwardcopies(repo['.'], repo[None], matcher)
62 64 # remove the copy files for which we already have copy info
63 65 added = [f for f in added if f not in copy]
64 66
65 67 return added, removed
66 68
67 69 def _findrenames(repo, matcher, added, removed, similarity):
68 70 """Find what files in added are really moved files.
69 71
70 72 Any file named in removed that is at least similarity% similar to a file
71 73 in added is seen as a rename.
72 74
73 75 """
74 76 renames = {}
75 77 if similarity > 0:
76 78 for src, dst, score in similar.findrenames(
77 79 repo, added, removed, similarity):
78 80 if repo.ui.verbose:
79 81 repo.ui.status(
80 82 _('detected move of %s as %s (%d%% similar)\n') % (
81 83 matcher.rel(src), matcher.rel(dst), score * 100))
82 84 renames[dst] = src
83 85 if renames:
84 86 repo.ui.status(_('detected move of %d files\n') % len(renames))
85 87 return renames
General Comments 0
You need to be logged in to leave comments. Login now