Patchwork D6848: narrow: add option for automatically removing unused includes

login
register
mail settings
Submitter phabricator
Date Sept. 17, 2019, 6:19 p.m.
Message ID <12be60e257c76d91270a30e192497aef@localhost.localdomain>
Download mbox | patch
Permalink /patch/41693/
State Not Applicable
Headers show

Comments

phabricator - Sept. 17, 2019, 6:19 p.m.
martinvonz updated this revision to Diff 16564.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D6848?vs=16563&id=16564

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D6848/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D6848

AFFECTED FILES
  hgext/narrow/narrowcommands.py
  tests/test-narrow-trackedcmd.t
  tests/test-narrow.t

CHANGE DETAILS




To: martinvonz, durin42, #hg-reviewers
Cc: pulkit, rdamazio, mercurial-devel

Patch

diff --git a/tests/test-narrow.t b/tests/test-narrow.t
--- a/tests/test-narrow.t
+++ b/tests/test-narrow.t
@@ -447,3 +447,48 @@ 
   abort: local changes found
   (use --force-delete-local-changes to ignore)
   [255]
+  $ cd ..
+
+Test --auto-remove-includes
+  $ hg clone --narrow ssh://user@dummy/master narrow-auto-remove -q \
+  > --include d0 --include d1 --include d2
+  $ cd narrow-auto-remove
+  $ echo a >> d0/f
+  $ hg ci -m 'local change to d0'
+  $ hg co '.^'
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ echo a >> d1/f
+  $ hg ci -m 'local change to d1'
+  created new head
+  $ hg debugobsolete $(hg log -T '{node}' -r 'desc("local change to d0")')
+  1 new obsolescence markers
+  obsoleted 1 changesets
+  $ echo n | hg tracked --auto-remove-includes --config ui.interactive=yes
+  comparing with ssh://user@dummy/master
+  searching for changes
+  looking for unused includes to remove
+  path:d0
+  path:d2
+  remove these unused includes (yn)? n
+  $ hg tracked --auto-remove-includes
+  comparing with ssh://user@dummy/master
+  searching for changes
+  looking for unused includes to remove
+  path:d0
+  path:d2
+  remove these unused includes (yn)? y
+  looking for local changes to affected paths
+  saved backup bundle to $TESTTMP/narrow-auto-remove/.hg/strip-backup/*-narrow.hg (glob)
+  deleting data/d0/f.i
+  deleting data/d2/f.i
+  deleting meta/d0/00manifest.i (tree !)
+  deleting meta/d2/00manifest.i (tree !)
+  $ hg tracked
+  I path:d1
+  $ hg files
+  d1/f
+  $ hg tracked --auto-remove-includes
+  comparing with ssh://user@dummy/master
+  searching for changes
+  looking for unused includes to remove
+  found no unused includes
diff --git a/tests/test-narrow-trackedcmd.t b/tests/test-narrow-trackedcmd.t
--- a/tests/test-narrow-trackedcmd.t
+++ b/tests/test-narrow-trackedcmd.t
@@ -101,6 +101,8 @@ 
   
       --addinclude VALUE [+]       new paths to include
       --removeinclude VALUE [+]    old paths to no longer include
+      --auto-remove-includes       automatically choose unused includes to
+                                   remove
       --addexclude VALUE [+]       new paths to exclude
       --import-rules VALUE         import narrowspecs from a file
       --removeexclude VALUE [+]    old paths to no longer exclude
diff --git a/hgext/narrow/narrowcommands.py b/hgext/narrow/narrowcommands.py
--- a/hgext/narrow/narrowcommands.py
+++ b/hgext/narrow/narrowcommands.py
@@ -328,6 +328,8 @@ 
 @command('tracked',
     [('', 'addinclude', [], _('new paths to include')),
      ('', 'removeinclude', [], _('old paths to no longer include')),
+     ('', 'auto-remove-includes', False,
+      _('automatically choose unused includes to remove')),
      ('', 'addexclude', [], _('new paths to exclude')),
      ('', 'import-rules', '', _('import narrowspecs from a file')),
      ('', 'removeexclude', [], _('old paths to no longer exclude')),
@@ -363,6 +365,11 @@ 
     If --clear is specified without any further options, the narrowspec will be
     empty and will not match any files.
 
+    If --auto-remove-includes is specified, then those includes that don't match
+    any files modified by currently visible local commits (those not shared by
+    the remote) will be added to the set of explicitly specified includes to
+    remove.
+
     --import-rules accepts a path to a file containing rules, allowing you to
     add --addinclude, --addexclude rules in bulk. Like the other include and
     exclude switches, the changes are applied immediately.
@@ -398,10 +405,12 @@ 
     removedincludes = narrowspec.parsepatterns(opts['removeinclude'])
     addedexcludes = narrowspec.parsepatterns(opts['addexclude'])
     removedexcludes = narrowspec.parsepatterns(opts['removeexclude'])
+    autoremoveincludes = opts['auto_remove_includes']
 
     update_working_copy = opts['update_working_copy']
     only_show = not (addedincludes or removedincludes or addedexcludes or
-                     removedexcludes or newrules or update_working_copy)
+                     removedexcludes or newrules or autoremoveincludes or
+                     update_working_copy)
 
     oldincludes, oldexcludes = repo.narrowpats
 
@@ -436,7 +445,7 @@ 
             narrowspec.copytoworkingcopy(repo)
         return 0
 
-    if not widening and not narrowing:
+    if not (widening or narrowing or autoremoveincludes):
         ui.status(_("nothing to widen or narrow\n"))
         return 0
 
@@ -459,6 +468,28 @@ 
 
         commoninc = discovery.findcommonincoming(repo, remote)
 
+        if autoremoveincludes:
+            outgoing = discovery.findcommonoutgoing(repo, remote,
+                                                    commoninc=commoninc)
+            ui.status(_('looking for unused includes to remove\n'))
+            localfiles = set()
+            for n in itertools.chain(outgoing.missing, outgoing.excluded):
+                localfiles.update(repo[n].files())
+            suggestedremovals = []
+            for include in sorted(oldincludes):
+                match = narrowspec.match(repo.root, [include], oldexcludes)
+                if not any(match(f) for f in localfiles):
+                    suggestedremovals.append(include)
+            if suggestedremovals:
+                for s in suggestedremovals:
+                    ui.status('%s\n' % s)
+                if (ui.promptchoice(_('remove these unused includes (yn)?'
+                                      '$$ &Yes $$ &No')) == 0):
+                    removedincludes.update(suggestedremovals)
+                    narrowing = True
+            else:
+                ui.status(_('found no unused includes\n'))
+
         if narrowing:
             newincludes = oldincludes - removedincludes
             newexcludes = oldexcludes | addedexcludes