[PATCH] Add should automatically add unversioned parents

Michael Ellerman michael at ellerman.id.au
Wed Aug 24 09:09:08 BST 2005


Hi Martin,

Here's an updated (bzr revno 1100) version of my patch to make smart_add
automatically add unversioned parents. It passes the few tests I've
added, although there's probably other cases I haven't thought of?

If you prefer, you can (hopefully) merge it from:
http://michael.ellerman.id.au/files/add-parents-automatically

( As an aside, having just waited 15 minutes for that branch to upload,
  it'd be cool to be able to upload a partial branch, ie. pointing mostly
  to the main bzr repo - I imagine that's already on the road map. )

cheers

*** modified file 'bzrlib/selftest/versioning.py'
--- bzrlib/selftest/versioning.py 
+++ bzrlib/selftest/versioning.py 
@@ -49,6 +49,54 @@
         self.assertEquals(delta.added[0][0], 'foo')
         self.failIf(delta.modified)
 
+
+class SmartAddInUnversioned(InTempDir):
+    def runTest(self):
+        """Try to add a file in an unversioned directory.
+
+        smart_add should add the parent(s) as necessary.
+        """
+        from bzrlib.branch import Branch
+        from bzrlib.commands import run_bzr
+        eq = self.assertEqual
+
+        b = Branch('.', init=True)
+
+        self.build_tree(['inertiatic/', 'inertiatic/esp'])
+        eq(list(b.unknowns()), ['inertiatic'])
+        run_bzr(['add', 'inertiatic/esp'])
+        eq(list(b.unknowns()), [])
+
+        # Multiple unversioned parents
+        self.build_tree(['veil/', 'veil/cerpin/', 'veil/cerpin/taxt'])
+        eq(list(b.unknowns()), ['veil'])
+        run_bzr(['add', 'veil/cerpin/taxt'])
+        eq(list(b.unknowns()), [])
+
+        # Check whacky paths work
+        self.build_tree(['cicatriz/', 'cicatriz/esp'])
+        eq(list(b.unknowns()), ['cicatriz'])
+        run_bzr(['add', 'inertiatic/../cicatriz/esp'])
+        eq(list(b.unknowns()), [])
+
+class SmartAddInVersioned(InTempDir):
+    def runTest(self):
+        """Try to add a file in a versioned directory.
+
+        smart_add should do this happily.
+        """
+        from bzrlib.branch import Branch
+        from bzrlib.commands import run_bzr
+        eq = self.assertEqual
+
+        b = Branch('.', init=True)
+
+        self.build_tree(['inertiatic/', 'inertiatic/esp'])
+        eq(list(b.unknowns()), ['inertiatic'])
+        run_bzr(['add', '--no-recurse', 'inertiatic'])
+        eq(list(b.unknowns()), ['inertiatic/esp'])
+        run_bzr(['add', 'inertiatic/esp'])
+        eq(list(b.unknowns()), [])
 
 
 class AddInUnversioned(InTempDir):

*** modified file 'bzrlib/add.py'
--- bzrlib/add.py 
+++ bzrlib/add.py 
@@ -15,6 +15,7 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 from trace import mutter, note
+import bzrlib.osutils
 
 def glob_expand_for_win32(file_list):
     import glob
@@ -39,10 +40,8 @@
     """
     import os
     import sys
-    from bzrlib.osutils import quotefn, kind_marker
     from bzrlib.errors import BadFileKindError, ForbiddenFileError
     import bzrlib.branch
-    import bzrlib.osutils
 
     if sys.platform == 'win32':
         file_list = glob_expand_for_win32(file_list)
@@ -82,12 +81,7 @@
         elif versioned:
             mutter("%r is already versioned" % f)
         else:
-            file_id = bzrlib.branch.gen_file_id(rf)
-            inv.add_path(rf, kind=kind, file_id=file_id)
-            mutter("added %r kind %r file_id={%s}" % (rf, kind, file_id))
-            count += 1 
-
-            print 'added', quotefn(f)
+            count += __add_one(b, inv, rf, kind, verbose)
 
         if kind == 'directory' and recurse:
             for subf in os.listdir(af):
@@ -107,3 +101,31 @@
     else:
         print "nothing new to add"
         # should this return 1 to the shell?
+
+
+def __add_one(branch, inv, rf, kind, verbose):
+    """Add a file or directory, automatically add unversioned parents."""
+    parts = bzrlib.osutils.splitpath(rf)
+
+    # already versioned
+    if inv.path2id(parts) != None:
+        return 0
+
+    if len(parts) > 0:
+        # add parent if not already versioned
+        parts.pop()
+        if len(parts) == 0:
+            subrf = ''
+        else:
+            subrf = bzrlib.osutils.joinpath(parts)
+
+        count = __add_one(branch, inv, subrf, 'directory', verbose)
+
+        file_id = bzrlib.branch.gen_file_id(rf)
+        inv.add_path(rf, kind=kind, file_id=file_id)
+
+        mutter("added %r kind %r file_id={%s}" % (rf, kind, file_id))
+
+    print 'added', bzrlib.osutils.quotefn(rf)
+
+    return count + 1

*** modified file 'bzrlib/commands.py'
--- bzrlib/commands.py 
+++ bzrlib/commands.py 
@@ -459,8 +459,10 @@
     Therefore simply saying 'bzr add' will version all files that
     are currently unknown.
 
-    TODO: Perhaps adding a file whose directly is not versioned should
-    recursively add that parent, rather than giving an error?
+    Adding a file whose parent directory is not versioned will
+    implicitly add the parent, and so on up to the root. This means
+    you should never need to explictly add a directory, they'll just
+    get added when you add a file in the directory.
     """
     takes_args = ['file*']
     takes_options = ['verbose', 'no-recurse']





More information about the bazaar mailing list