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