[PATCH 3 of 3 RFC] revert: add support for reverting added subrepos

Angel Ezquerra angel.ezquerra at gmail.com
Thu Mar 22 17:34:39 CDT 2012


# HG changeset patch
# User Angel Ezquerra <angel.ezquerra at gmail.com>
# Date 1332370741 -3600
# Node ID 81a9f35cf00ff7b62293bdd3e7cbbdcbc23add55
# Parent  4f3b203e770e8a738d84eb9e006e124718ee4cf5
revert: add support for reverting added subrepos

Detect subrepos that are found on the working directory but not on the parent
revision. This means that they have been added to the .hgsub file (and possibly
to the .hgsubstate file).

To "remove them", parse the .hgsub and .hgsubstate files and remove any lines
that refert to the added subrepo.

NOTES / ISSUES:

* The "command.removesub" function could be folded into the remove command.
* Is modifying the .hgsub and .hgsubstate files automatically OK?
* This may change the line endings on the .hgsub and .hgsubstate files

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -4606,6 +4606,69 @@
 
     return ret
 
+def removesub(ui, repo, spath):
+    # remove the corresponding lines from the .hgsub and .hgsubstate files
+    ui.status(_('removing subrepo %s\n') % spath)
+
+    spath = os.path.normcase(spath)
+    hgsubpath = repo.wjoin('.hgsub')
+    hgsubstatepath = repo.wjoin('.hgsubstate')
+
+    try:
+        h = open(hgsubpath, 'r')
+        hgsub = h.readlines()
+        h.close()
+    except:
+        ui.warn(_('could not open .hgsub file for reading'))
+        return
+
+    try:
+        h = open(hgsubstatepath, 'r')
+        hgsubstate = h.readlines()
+        h.close()
+    except:
+        ui.warn(_('could not open .hgsubstate file for reading'))
+        return
+
+    # filter any lines that refer to the selected subrepo
+    def filterlines(lines, filterfunc):
+        filteredlines = []
+        for line in lines:
+            if filterfunc(line):
+                continue
+            filteredlines.append(line)
+        return filteredlines
+
+    def hgsubmatch(line):
+        subpath = os.path.normcase(line.split('=')[0].strip())
+        return subpath == spath
+
+    def hgsubstatematch(line):
+        subpath = line.split()[1].strip()
+        return subpath == spath
+
+    newhgsub = filterlines(hgsub, hgsubmatch)
+    if len(newhgsub) == len(hgsub):
+        ui.warn(_('repository %s is not present on .hgsub file') % spath)
+        return
+
+    # it does not matter if the subrepo is not found on the .hgsubsate file
+    newhgsubstate = filterlines(hgsubstate, hgsubstatematch)
+
+    # Update the .hgsub and .hgsubstate files
+    outdata = [(hgsubpath, newhgsub)]
+    if len(newhgsubstate) != len(hgsubstate):
+        outdata.append((hgsubstatepath, newhgsubstate))
+
+    for fname, lines in outdata:
+        try:
+            h = open(fname, 'w')
+            h.writelines(lines)
+            h.close()
+        except:
+            ui.warn(_('could not open %s file for writing') % fname)
+            return
+
 @command('rename|move|mv',
     [('A', 'after', None, _('record a rename that has already occurred')),
     ('f', 'force', None, _('forcibly copy over an existing managed file')),
@@ -4819,12 +4882,15 @@
         m.bad = lambda x, y: False
         for abs in repo.walk(m):
             names[abs] = m.rel(abs), m.exact(abs)
+        wdsubs = [s for s in repo[None].substate if m(s)]
 
         # walk target manifest.
 
         def badfn(path, msg):
             if path in names:
                 return
+            if path in wdsubs:
+                return
             if path in repo[node].substate:
                 return
             path_ = path + '/'
@@ -4970,7 +5036,7 @@
                 checkout(f)
                 normal(f)
 
-            if targetsubs:
+            if targetsubs or wdsubs:
                 # Revert the subrepos on the revert list
                 # reverting a subrepo is a 2 step process:
                 # 1. if the no_backup is not set, revert all modified files inside the subrepo
@@ -4994,6 +5060,11 @@
                             revert(ui, ctx.sub(sname)._repo, 'set:modified()', **revert_opts)
                     # Update the repo to the revision specified in the parent repo revision
                     ctx.sub(sname).get(ctx.substate[sname], overwrite=True)
+
+                for sname in wdsubs:
+                    if sname not in targetsubs:
+                        removesub(ui, repo, sname)
+
     finally:
         wlock.release()
 


More information about the Mercurial-devel mailing list