[Pkg-bazaar-commits] ./bzr/unstable r70: Prepare for smart recursive add.

mbp at sourcefrog.net mbp at sourcefrog.net
Fri Apr 10 07:27:31 UTC 2009


------------------------------------------------------------
revno: 70
committer: mbp at sourcefrog.net
timestamp: Wed 2005-03-23 14:09:50 +1100
message:
  Prepare for smart recursive add.
  
  - New Inventory.add_path, so that callers don't need to know so much
    about path lookup.
  
  - Make gen_file_id public.
  
  - New add module and smart_add function; does previous add operations
    more cleanly but not recursive mode yet.
  
  - New warning() function.
added:
  bzrlib/add.py
modified:
  bzrlib/__init__.py
  bzrlib/branch.py
  bzrlib/commands.py
  bzrlib/inventory.py
  bzrlib/trace.py
  bzrlib/tree.py
-------------- next part --------------
=== modified file 'bzrlib/__init__.py'
--- a/bzrlib/__init__.py	2005-03-09 04:46:15 +0000
+++ b/bzrlib/__init__.py	2005-03-23 03:09:50 +0000
@@ -22,6 +22,8 @@
 from osutils import format_date
 from tree import Tree
 from diff import diff_trees
+from trace import mutter, warning
+import add
 
 BZRDIR = ".bzr"
 

=== added file 'bzrlib/add.py'
--- a/bzrlib/add.py	1970-01-01 00:00:00 +0000
+++ b/bzrlib/add.py	2005-03-23 03:09:50 +0000
@@ -0,0 +1,68 @@
+# Copyright (C) 2005 Canonical Ltd
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+import types, os, sys, stat
+import bzrlib
+
+from osutils import quotefn
+from errors import bailout
+
+def smart_add(file_list, verbose=False, recurse=False):
+    """Add files to version, optionall recursing into directories.
+
+    This is designed more towards DWIM for humans than API simplicity.
+    For the specific behaviour see the help for cmd_add().
+    """
+    assert file_list
+    assert not isinstance(file_list, types.StringTypes)
+    b = bzrlib.branch.Branch(file_list[0], find_root=True)
+    inv = b.read_working_inventory()
+    dirty = False
+
+    for f in file_list:
+        rf = b.relpath(f)
+        af = b.abspath(rf)
+
+        bzrlib.mutter("smart add of %r" % f)
+        
+        if bzrlib.branch.is_control_file(af):
+            bailout("cannot add control file %r" % af)
+
+        kind = bzrlib.osutils.file_kind(f)
+        if kind == 'file':
+            if inv.path2id(rf):
+                bzrlib.warning("%r is already versioned" % f)
+                continue
+        elif kind == 'directory':
+            if inv.path2id(rf):
+                if not recurse:
+                    bzrlib.warning("%r is already versioned" % f)
+                    continue
+                else:
+                    # TODO: don't add, but recurse down
+                    continue
+        else:
+            bailout("can't smart_add file kind %r" % kind)
+
+        file_id = bzrlib.branch.gen_file_id(rf)
+        inv.add_path(rf, kind=kind, file_id=file_id)
+        bzrlib.mutter("added %r kind %r file_id={%s}" % (rf, kind, file_id))
+        dirty = True
+        if verbose:
+            bzrlib.textui.show_status('A', kind, quotefn(f))
+
+    if dirty:
+        b._write_inventory(inv)

=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py	2005-03-22 08:00:50 +0000
+++ b/bzrlib/branch.py	2005-03-23 03:09:50 +0000
@@ -1,3 +1,5 @@
+# Copyright (C) 2005 Canonical Ltd
+
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 2 of the License, or
@@ -202,6 +204,7 @@
         will be committed to the next revision.
         """
         ## TODO: factor out to atomicfile?  is rename safe on windows?
+        ## TODO: Maybe some kind of clean/dirty marker on inventory?
         tmpfname = self.controlfilename('inventory.tmp')
         tmpf = file(tmpfname, 'w')
         inv.write_xml(tmpf)
@@ -272,30 +275,23 @@
                 
             fullpath = os.path.normpath(self.abspath(f))
 
-            if isfile(fullpath):
-                kind = 'file'
-            elif isdir(fullpath):
-                kind = 'directory'
-            else:
-                bailout('cannot add: not a regular file or directory: %s' % quotefn(f))
-
-            if len(fp) > 1:
-                parent_name = joinpath(fp[:-1])
-                mutter("lookup parent %r" % parent_name)
-                parent_id = inv.path2id(parent_name)
-                if parent_id == None:
-                    bailout("cannot add: parent %r is not versioned"
-                            % joinpath(fp[:-1]))
-            else:
-                parent_id = None
-
-            file_id = _gen_file_id(fp[-1])
-            inv.add(InventoryEntry(file_id, fp[-1], kind=kind, parent_id=parent_id))
+            try:
+                kind = file_kind(fullpath)
+            except OSError:
+                # maybe something better?
+                bailout('cannot add: not a regular file or directory: %s' % quotefn(f))
+            
+            if kind != 'file' and kind != 'directory':
+                bailout('cannot add: not a regular file or directory: %s' % quotefn(f))
+
+            file_id = gen_file_id(f)
+            inv.add_path(f, kind=kind, file_id=file_id)
+
             if verbose:
                 show_status('A', kind, quotefn(f))
                 
-            mutter("add file %s file_id:{%s} kind=%r parent_id={%s}"
-                   % (f, file_id, kind, parent_id))
+            mutter("add file %s file_id:{%s} kind=%r" % (f, file_id, kind))
+            
         self._write_inventory(inv)
 
 
@@ -476,7 +472,7 @@
                            entry.text_id)
                     
                 else:
-                    entry.text_id = _gen_file_id(entry.name)
+                    entry.text_id = gen_file_id(entry.name)
                     self.text_store.add(content, entry.text_id)
                     mutter('    stored with text_id {%s}' % entry.text_id)
                     if verbose:
@@ -798,6 +794,8 @@
         ## mutter('check %r for control file' % ((head, tail), ))
         if tail == bzrlib.BZRDIR:
             return True
+        if filename == head:
+            break
         filename = head
     return False
 
@@ -810,15 +808,18 @@
     return s
 
 
-def _gen_file_id(name):
+def gen_file_id(name):
     """Return new file id.
 
     This should probably generate proper UUIDs, but for the moment we
     cope with just randomness because running uuidgen every time is
     slow."""
-    assert '/' not in name
-    while name[0] == '.':
-        name = name[1:]
+    idx = name.rfind('/')
+    if idx != -1:
+        name = name[idx+1 : ]
+
+    name = name.lstrip('.')
+
     s = hexlify(rand_bytes(8))
     return '-'.join((name, compact_date(time.time()), s))
 

=== modified file 'bzrlib/commands.py'
--- a/bzrlib/commands.py	2005-03-22 11:43:02 +0000
+++ b/bzrlib/commands.py	2005-03-23 03:09:50 +0000
@@ -165,15 +165,34 @@
     print Branch('.').revno()
     
 
+    
 def cmd_add(file_list, verbose=False):
-    """Add specified files.
+    """Add specified files or directories.
+
+    In non-recursive mode, all the named items are added, regardless
+    of whether they were previously ignored.  A warning is given if
+    any of the named files are already versioned.
+
+    In recursive mode (the default), files are treated the same way
+    but the behaviour for directories is different.  Directories that
+    are already versioned do not give a warning.  All directories,
+    whether already versioned or not, are searched for files or
+    subdirectories that are neither versioned or ignored, and these
+    are added.  This search proceeds recursively into versioned
+    directories.
+
+    Therefore simply saying 'bzr add .' will version all files that
+    are currently unknown.
+    """
+    if True:
+        bzrlib.add.smart_add(file_list, verbose)
+    else:
+        # old way
+        assert file_list
+        b = Branch(file_list[0], find_root=True)
+        b.add([b.relpath(f) for f in file_list], verbose=verbose)
+
     
-    Fails if the files are already added.
-    """
-    assert file_list
-    b = Branch(file_list[0], find_root=True)
-    b.add([b.relpath(f) for f in file_list], verbose=verbose)
-
 
 def cmd_relpath(filename):
     print Branch(filename).relpath(filename)
@@ -508,7 +527,7 @@
     bzrlib.trace.verbose = False
 
     for m in bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, \
-        bzrlib.tree, bzrlib.tests, bzrlib.commands:
+        bzrlib.tree, bzrlib.tests, bzrlib.commands, bzrlib.add:
         mf, mt = doctest.testmod(m)
         failures += mf
         tests += mt

=== modified file 'bzrlib/inventory.py'
--- a/bzrlib/inventory.py	2005-03-12 07:38:31 +0000
+++ b/bzrlib/inventory.py	2005-03-23 03:09:50 +0000
@@ -31,8 +31,10 @@
 
 from xml import XMLMixin
 from errors import bailout
-from osutils import uuid, quotefn, splitpath, joinpath, appendpath
-from trace import mutter
+
+import bzrlib
+from bzrlib.osutils import uuid, quotefn, splitpath, joinpath, appendpath
+from bzrlib.trace import mutter
 
 class InventoryEntry(XMLMixin):
     """Description of a versioned file.
@@ -360,6 +362,23 @@
             self._tree[entry.file_id] = {}
 
 
+    def add_path(self, relpath, kind, file_id=None):
+        """Add entry from a path.
+
+        The immediate parent must already be versioned"""
+        parts = bzrlib.osutils.splitpath(relpath)
+        if len(parts) == 0:
+            bailout("cannot re-add root of inventory")
+
+        if file_id is None:
+            file_id = bzrlib.branch.gen_file_id(relpath)
+
+        parent_id = self.path2id(parts[:-1])
+        ie = InventoryEntry(file_id, parts[-1],
+                            kind=kind, parent_id=parent_id)
+        return self.add(ie)
+
+
     def __delitem__(self, file_id):
         """Remove entry by id.
 
@@ -468,10 +487,11 @@
         This returns the entry of the last component in the path,
         which may be either a file or a directory.
         """
-        assert isinstance(name, types.StringTypes)
+        if isinstance(name, types.StringTypes):
+            name = splitpath(name)
 
         parent_id = None
-        for f in splitpath(name):
+        for f in name:
             try:
                 cie = self._tree[parent_id][f]
                 assert cie.name == f
@@ -497,6 +517,8 @@
 
 
 
+
+
 if __name__ == '__main__':
     import doctest, inventory
     doctest.testmod(inventory)

=== modified file 'bzrlib/trace.py'
--- a/bzrlib/trace.py	2005-03-22 01:17:00 +0000
+++ b/bzrlib/trace.py	2005-03-23 03:09:50 +0000
@@ -41,6 +41,12 @@
 verbose = False
 
 
+def warning(msg):
+    b = 'bzr: warning: ' + msg + '\n'
+    sys.stderr.write(b)
+    _tracefile.write(b)
+    _tracefile.flush()
+
 def mutter(msg):
     _tracefile.write(msg)
     _tracefile.write('\n')

=== modified file 'bzrlib/tree.py'
--- a/bzrlib/tree.py	2005-03-22 07:28:45 +0000
+++ b/bzrlib/tree.py	2005-03-23 03:09:50 +0000
@@ -1,5 +1,4 @@
-#! /usr/bin/env python
-# -*- coding: UTF-8 -*-
+# Copyright (C) 2005 Canonical Ltd
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by



More information about the Pkg-bazaar-commits mailing list