##// END OF EJS Templates
automv: improve function docstrings
Martijn Pieters -
r28149:d356d525 default
parent child Browse files
Show More
@@ -1,81 +1,92
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 disabled = opts.pop('no_automv', False)
36 disabled = opts.pop('no_automv', False)
36 if not disabled:
37 if not disabled:
37 threshold = float(ui.config('automv', 'similarity', '1.00'))
38 threshold = float(ui.config('automv', 'similarity', '1.00'))
38 if threshold > 0:
39 if threshold > 0:
39 match = scmutil.match(repo[None], pats, opts)
40 match = scmutil.match(repo[None], pats, opts)
40 added, removed = _interestingfiles(repo, match)
41 added, removed = _interestingfiles(repo, match)
41 renames = _findrenames(repo, match, added, removed, threshold)
42 renames = _findrenames(repo, match, added, removed, threshold)
42 _markchanges(repo, renames)
43 _markchanges(repo, renames)
43
44
44 return orig(ui, repo, *pats, **opts)
45 return orig(ui, repo, *pats, **opts)
45
46
46 def _interestingfiles(repo, matcher):
47 def _interestingfiles(repo, matcher):
48 """Find what files were added or removed in this commit.
49
50 Returns a tuple of two lists: (added, removed). Only files not *already*
51 marked as moved are included in the added list.
52
53 """
47 stat = repo.status(match=matcher)
54 stat = repo.status(match=matcher)
48 added = stat[1]
55 added = stat[1]
49 removed = stat[2]
56 removed = stat[2]
50
57
51 copy = copies._forwardcopies(repo['.'], repo[None], matcher)
58 copy = copies._forwardcopies(repo['.'], repo[None], matcher)
52 # remove the copy files for which we already have copy info
59 # remove the copy files for which we already have copy info
53 added = [f for f in added if f not in copy]
60 added = [f for f in added if f not in copy]
54
61
55 return added, removed
62 return added, removed
56
63
57 def _findrenames(repo, matcher, added, removed, similarity):
64 def _findrenames(repo, matcher, added, removed, similarity):
58 """Find renames from removed files of the current commit/amend files
65 """Find what files in added are really moved files.
59 to the added ones"""
66
67 Any file named in removed that is at least similarity% similar to a file
68 in added is seen as a rename.
69
70 """
60 renames = {}
71 renames = {}
61 if similarity > 0:
72 if similarity > 0:
62 for src, dst, score in similar.findrenames(
73 for src, dst, score in similar.findrenames(
63 repo, added, removed, similarity):
74 repo, added, removed, similarity):
64 if repo.ui.verbose:
75 if repo.ui.verbose:
65 repo.ui.status(
76 repo.ui.status(
66 _('detected move of %s as %s (%d%% similar)\n') % (
77 _('detected move of %s as %s (%d%% similar)\n') % (
67 matcher.rel(src), matcher.rel(dst), score * 100))
78 matcher.rel(src), matcher.rel(dst), score * 100))
68 renames[dst] = src
79 renames[dst] = src
69 if renames:
80 if renames:
70 repo.ui.status(_('detected move of %d files\n') % len(renames))
81 repo.ui.status(_('detected move of %d files\n') % len(renames))
71 return renames
82 return renames
72
83
73 def _markchanges(repo, renames):
84 def _markchanges(repo, renames):
74 """Marks the files in renames as copied."""
85 """Marks the files in renames as copied."""
75 wctx = repo[None]
86 wctx = repo[None]
76 wlock = repo.wlock()
87 wlock = repo.wlock()
77 try:
88 try:
78 for dst, src in renames.iteritems():
89 for dst, src in renames.iteritems():
79 wctx.copy(src, dst)
90 wctx.copy(src, dst)
80 finally:
91 finally:
81 wlock.release()
92 wlock.release()
General Comments 0
You need to be logged in to leave comments. Login now