[Pkg-bazaar-commits] ./bzr/unstable r178: - Use a non-null file_id for the branch root directory. At the moment

mbp at sourcefrog.net mbp at sourcefrog.net
Fri Apr 10 07:51:18 UTC 2009


------------------------------------------------------------
revno: 178
committer: mbp at sourcefrog.net
timestamp: Wed 2005-04-06 13:38:35 +1000
message:
  - Use a non-null file_id for the branch root directory.  At the moment
    this is fixed; in the future it should be stored in the directory
    and perhaps be randomized at each branch init.  It is not written
    out to the inventory at all as yet.
  
  - Various branch code cleanups to support this.
  
  - If an exception occurs, log traceback into .bzr.log and print a
    message saying it's there.
  
  - New file-id-path command and more help.
  
  - Some pychecker fixups.
  
  - InventoryEntry constructor parameters now require an entry kind and
    a parent_id.
  
  - Fix up cat command when reading a file from a previous revision.
modified:
  bzrlib/branch.py
  bzrlib/commands.py
  bzrlib/diff.py
  bzrlib/inventory.py
  bzrlib/osutils.py
  bzrlib/tree.py
-------------- next part --------------
=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py	2005-04-06 02:05:46 +0000
+++ b/bzrlib/branch.py	2005-04-06 03:38:35 +0000
@@ -304,7 +304,11 @@
     def print_file(self, file, revno):
         """Print `file` to stdout."""
         tree = self.revision_tree(self.lookup_revision(revno))
-        tree.print_file(self.inventory.path2id(file))
+        # use inventory as it was in that revision
+        file_id = tree.inventory.path2id(file)
+        if not file_id:
+            bailout("%r is not present in revision %d" % (file, revno))
+        tree.print_file(file_id)
         
 
     def remove(self, files, verbose=False):

=== modified file 'bzrlib/commands.py'
--- a/bzrlib/commands.py	2005-04-06 02:05:46 +0000
+++ b/bzrlib/commands.py	2005-04-06 03:38:35 +0000
@@ -264,14 +264,38 @@
 
 
 def cmd_file_id(filename):
+    """Print file_id of a particular file or directory.
+
+usage: bzr file-id FILE
+
+The file_id is assigned when the file is first added and remains the
+same through all revisions where the file exists, even when it is
+moved or renamed.
+"""
     b = Branch(filename)
     i = b.inventory.path2id(b.relpath(filename))
-    if i is None:
-        bailout("%s is not a versioned file" % filename)
+    if i == None:
+        bailout("%r is not a versioned file" % filename)
     else:
         print i
 
 
+def cmd_file_id_path(filename):
+    """Print path of file_ids to a file or directory.
+
+usage: bzr file-id-path FILE
+
+This prints one line for each directory down to the target,
+starting at the branch root."""
+    b = Branch(filename)
+    inv = b.inventory
+    fid = inv.path2id(b.relpath(filename))
+    if fid == None:
+        bailout("%r is not a versioned file" % filename)
+    for fip in inv.get_idpath(fid):
+        print fip
+
+
 def cmd_find_filename(fileid):
     n = find_filename(fileid)
     if n is None:
@@ -748,6 +772,7 @@
     'diff':                   [],
     'export':                 ['revno', 'dest'],
     'file-id':                ['filename'],
+    'file-id-path':           ['filename'],
     'get-file-text':          ['text_id'],
     'get-inventory':          ['inventory_id'],
     'get-revision':           ['revision_id'],
@@ -971,6 +996,8 @@
         if len(e.args) > 1:
             for h in e.args[1]:
                 log_error('  ' + h + '\n')
+        traceback.print_exc(None, bzrlib.trace._tracefile)
+        log_error('see ~/.bzr.log for more information\n')
         return 1
     except Exception, e:
         log_error('bzr: exception: %s\n' % e)

=== modified file 'bzrlib/diff.py'
--- a/bzrlib/diff.py	2005-03-09 04:08:15 +0000
+++ b/bzrlib/diff.py	2005-04-06 03:38:35 +0000
@@ -121,6 +121,7 @@
             old_item = next(old_it)
         else:
             assert old_id == new_id
+            assert old_id != None
             assert old_name == new_name
             assert old_kind == new_kind
 

=== modified file 'bzrlib/inventory.py'
--- a/bzrlib/inventory.py	2005-04-05 09:05:32 +0000
+++ b/bzrlib/inventory.py	2005-04-06 03:38:35 +0000
@@ -18,9 +18,14 @@
 
 # TODO: Maybe store inventory_id in the file?  Not really needed.
 
-__copyright__ = "Copyright (C) 2005 Canonical Ltd."
 __author__ = "Martin Pool <mbp at canonical.com>"
 
+
+# This should really be an id randomly assigned when the tree is
+# created, but it's not for now.
+ROOT_ID = "TREE_ROOT"
+
+
 import sys, os.path, types, re
 from sets import Set
 
@@ -59,24 +64,25 @@
 
     >>> i = Inventory()
     >>> i.path2id('')
-    >>> i.add(InventoryEntry('123', 'src', kind='directory'))
-    >>> i.add(InventoryEntry('2323', 'hello.c', parent_id='123'))
+    'TREE_ROOT'
+    >>> i.add(InventoryEntry('123', 'src', 'directory', ROOT_ID))
+    >>> i.add(InventoryEntry('2323', 'hello.c', 'file', parent_id='123'))
     >>> for j in i.iter_entries():
     ...   print j
     ... 
-    ('src', InventoryEntry('123', 'src', kind='directory', parent_id=None))
+    ('src', InventoryEntry('123', 'src', kind='directory', parent_id='TREE_ROOT'))
     ('src/hello.c', InventoryEntry('2323', 'hello.c', kind='file', parent_id='123'))
-    >>> i.add(InventoryEntry('2323', 'bye.c', parent_id='123'))
+    >>> i.add(InventoryEntry('2323', 'bye.c', 'file', '123'))
     Traceback (most recent call last):
     ...
     BzrError: ('inventory already contains entry with id {2323}', [])
-    >>> i.add(InventoryEntry('2324', 'bye.c', parent_id='123'))
-    >>> i.add(InventoryEntry('2325', 'wibble', parent_id='123', kind='directory'))
+    >>> i.add(InventoryEntry('2324', 'bye.c', 'file', '123'))
+    >>> i.add(InventoryEntry('2325', 'wibble', 'directory', '123'))
     >>> i.path2id('src/wibble')
     '2325'
     >>> '2325' in i
     True
-    >>> i.add(InventoryEntry('2326', 'wibble.c', parent_id='2325'))
+    >>> i.add(InventoryEntry('2326', 'wibble.c', 'file', '2325'))
     >>> i['2326']
     InventoryEntry('2326', 'wibble.c', kind='file', parent_id='2325')
     >>> for j in i.iter_entries():
@@ -95,19 +101,22 @@
            But those depend on its position within a particular inventory, and
            it would be nice not to need to hold the backpointer here.
     """
-    def __init__(self, file_id, name, kind='file', text_id=None,
-                 parent_id=None):
+
+    # TODO: split InventoryEntry into subclasses for files,
+    # directories, etc etc.
+    
+    def __init__(self, file_id, name, kind, parent_id, text_id=None):
         """Create an InventoryEntry
         
         The filename must be a single component, relative to the
         parent directory; it cannot be a whole path or relative name.
 
-        >>> e = InventoryEntry('123', 'hello.c')
+        >>> e = InventoryEntry('123', 'hello.c', 'file', ROOT_ID)
         >>> e.name
         'hello.c'
         >>> e.file_id
         '123'
-        >>> e = InventoryEntry('123', 'src/hello.c')
+        >>> e = InventoryEntry('123', 'src/hello.c', 'file', ROOT_ID)
         Traceback (most recent call last):
         BzrError: ("InventoryEntry name is not a simple filename: 'src/hello.c'", [])
         """
@@ -126,6 +135,8 @@
         self.text_size = None
         if kind == 'directory':
             self.children = {}
+        else:
+            assert kind == 'file'
 
 
     def sorted_children(self):
@@ -136,7 +147,7 @@
 
     def copy(self):
         other = InventoryEntry(self.file_id, self.name, self.kind,
-                               self.text_id, self.parent_id)
+                               self.parent_id, text_id=self.text_id)
         other.text_sha1 = self.text_sha1
         other.text_size = self.text_size
         return other
@@ -159,14 +170,21 @@
         e.set('file_id', self.file_id)
         e.set('kind', self.kind)
 
-        if self.text_size is not None:
+        if self.text_size != None:
             e.set('text_size', '%d' % self.text_size)
             
-        for f in ['text_id', 'text_sha1', 'parent_id']:
+        for f in ['text_id', 'text_sha1']:
             v = getattr(self, f)
-            if v is not None:
+            if v != None:
                 e.set(f, v)
 
+        # to be conservative, we don't externalize the root pointers
+        # for now, leaving them as null in the xml form.  in a future
+        # version it will be implied by nested elements.
+        if self.parent_id != ROOT_ID:
+            assert isinstance(self.parent_id, basestring)
+            e.set('parent_id', self.parent_id)
+
         e.tail = '\n'
             
         return e
@@ -174,10 +192,17 @@
 
     def from_element(cls, elt):
         assert elt.tag == 'entry'
-        self = cls(elt.get('file_id'), elt.get('name'), elt.get('kind'))
+
+        ## original format inventories don't have a parent_id for
+        ## nodes in the root directory, but it's cleaner to use one
+        ## internally.
+        parent_id = elt.get('parent_id')
+        if parent_id == None:
+            parent_id = ROOT_ID
+
+        self = cls(elt.get('file_id'), elt.get('name'), elt.get('kind'), parent_id)
         self.text_id = elt.get('text_id')
         self.text_sha1 = elt.get('text_sha1')
-        self.parent_id = elt.get('parent_id')
         
         ## mutter("read inventoryentry: %r" % (elt.attrib))
 
@@ -247,7 +272,7 @@
     >>> inv.write_xml(sys.stdout)
     <inventory>
     </inventory>
-    >>> inv.add(InventoryEntry('123-123', 'hello.c'))
+    >>> inv.add(InventoryEntry('123-123', 'hello.c', 'file', ROOT_ID))
     >>> inv['123-123'].name
     'hello.c'
 
@@ -291,8 +316,8 @@
         The inventory is created with a default root directory, with
         an id of None.
         """
-        self.root = RootEntry(None)
-        self._byid = {None: self.root}
+        self.root = RootEntry(ROOT_ID)
+        self._byid = {self.root.file_id: self.root}
 
 
     def __iter__(self):
@@ -322,7 +347,7 @@
                     
 
 
-    def directories(self, from_dir=None):
+    def directories(self):
         """Return (path, entry) pairs for all directories.
         """
         def descend(parent_ie):
@@ -349,7 +374,7 @@
         """True if this entry contains a file with given id.
 
         >>> inv = Inventory()
-        >>> inv.add(InventoryEntry('123', 'foo.c'))
+        >>> inv.add(InventoryEntry('123', 'foo.c', 'file', ROOT_ID))
         >>> '123' in inv
         True
         >>> '456' in inv
@@ -362,11 +387,17 @@
         """Return the entry for given file_id.
 
         >>> inv = Inventory()
-        >>> inv.add(InventoryEntry('123123', 'hello.c'))
+        >>> inv.add(InventoryEntry('123123', 'hello.c', 'file', ROOT_ID))
         >>> inv['123123'].name
         'hello.c'
         """
-        return self._byid[file_id]
+        if file_id == None:
+            bailout("can't look up file_id None")
+            
+        try:
+            return self._byid[file_id]
+        except KeyError:
+            bailout("file_id {%s} not in inventory" % file_id)
 
 
     def get_child(self, parent_id, filename):
@@ -384,7 +415,7 @@
         try:
             parent = self._byid[entry.parent_id]
         except KeyError:
-            bailout("parent_id %r not in inventory" % entry.parent_id)
+            bailout("parent_id {%s} not in inventory" % entry.parent_id)
 
         if parent.children.has_key(entry.name):
             bailout("%s is already versioned" %
@@ -402,10 +433,11 @@
         if len(parts) == 0:
             bailout("cannot re-add root of inventory")
 
-        if file_id is None:
+        if file_id == None:
             file_id = bzrlib.branch.gen_file_id(relpath)
 
         parent_id = self.path2id(parts[:-1])
+        assert parent_id != None
         ie = InventoryEntry(file_id, parts[-1],
                             kind=kind, parent_id=parent_id)
         return self.add(ie)
@@ -415,7 +447,7 @@
         """Remove entry by id.
 
         >>> inv = Inventory()
-        >>> inv.add(InventoryEntry('123', 'foo.c'))
+        >>> inv.add(InventoryEntry('123', 'foo.c', 'file', ROOT_ID))
         >>> '123' in inv
         True
         >>> del inv['123']
@@ -454,7 +486,7 @@
         """Construct from XML Element
 
         >>> inv = Inventory()
-        >>> inv.add(InventoryEntry('foo.c-123981239', 'foo.c'))
+        >>> inv.add(InventoryEntry('foo.c-123981239', 'foo.c', 'file', ROOT_ID))
         >>> elt = inv.to_element()
         >>> inv2 = Inventory.from_element(elt)
         >>> inv2 == inv
@@ -476,10 +508,10 @@
         >>> i2 = Inventory()
         >>> i1 == i2
         True
-        >>> i1.add(InventoryEntry('123', 'foo'))
+        >>> i1.add(InventoryEntry('123', 'foo', 'file', ROOT_ID))
         >>> i1 == i2
         False
-        >>> i2.add(InventoryEntry('123', 'foo'))
+        >>> i2.add(InventoryEntry('123', 'foo', 'file', ROOT_ID))
         >>> i1 == i2
         True
         """
@@ -505,11 +537,14 @@
         The list contains one element for each directory followed by
         the id of the file itself.  So the length of the returned list
         is equal to the depth of the file in the tree, counting the
-        root directory as depth 0.
+        root directory as depth 1.
         """
         p = []
         while file_id != None:
-            ie = self._byid[file_id]
+            try:
+                ie = self._byid[file_id]
+            except KeyError:
+                bailout("file_id {%s} not found in inventory" % file_id)
             p.insert(0, ie.file_id)
             file_id = ie.parent_id
         return p
@@ -517,11 +552,9 @@
 
     def id2path(self, file_id):
         """Return as a list the path to file_id."""
-        p = []
-        while file_id != None:
-            ie = self._byid[file_id]
-            p.insert(0, ie.name)
-            file_id = ie.parent_id
+
+        # get all names, skipping root
+        p = [self[fid].name for fid in self.get_idpath(file_id)[1:]]
         return '/'.join(p)
             
 
@@ -534,15 +567,20 @@
 
         This returns the entry of the last component in the path,
         which may be either a file or a directory.
+
+        Returns None iff the path is not found.
         """
         if isinstance(name, types.StringTypes):
             name = splitpath(name)
 
-        parent = self[None]
+        mutter("lookup path %r" % name)
+
+        parent = self.root
         for f in name:
             try:
                 cie = parent.children[f]
                 assert cie.name == f
+                assert cie.parent_id == parent.file_id
                 parent = cie
             except KeyError:
                 # or raise an error?
@@ -595,9 +633,3 @@
 
 def is_valid_name(name):
     return bool(_NAME_RE.match(name))
-
-
-
-if __name__ == '__main__':
-    import doctest, inventory
-    doctest.testmod(inventory)

=== modified file 'bzrlib/osutils.py'
--- a/bzrlib/osutils.py	2005-03-29 02:31:34 +0000
+++ b/bzrlib/osutils.py	2005-04-06 03:38:35 +0000
@@ -269,7 +269,7 @@
     BzrError: ("sorry, '..' not allowed in path", [])
     """
     assert isinstance(p, types.StringTypes)
-    ps = [f for f in p.split('/') if f != '.']
+    ps = [f for f in p.split('/') if (f != '.' and f != '')]
     for f in ps:
         if f == '..':
             bailout("sorry, %r not allowed in path" % f)

=== modified file 'bzrlib/tree.py'
--- a/bzrlib/tree.py	2005-04-06 02:05:46 +0000
+++ b/bzrlib/tree.py	2005-04-06 03:38:35 +0000
@@ -157,6 +157,7 @@
         return file(self.abspath(filename), 'rb')
 
     def _get_store_filename(self, file_id):
+        ## XXX: badly named; this isn't in the store at all
         return self.abspath(self.id2path(file_id))
 
     def has_id(self, file_id):
@@ -194,7 +195,7 @@
         """
         inv = self.inventory
 
-        def descend(from_dir, from_dir_id, dp):
+        def descend(from_dir_relpath, from_dir_id, dp):
             ls = os.listdir(dp)
             ls.sort()
             for f in ls:
@@ -205,7 +206,7 @@
                     continue
 
                 # path within tree
-                fp = appendpath(from_dir, f)
+                fp = appendpath(from_dir_relpath, f)
 
                 # absolute path
                 fap = appendpath(dp, f)
@@ -237,7 +238,7 @@
                 for ff in descend(fp, f_ie.file_id, fap):
                     yield ff
 
-        for f in descend('', None, self.basedir):
+        for f in descend('', inv.root.file_id, self.basedir):
             yield f
             
 



More information about the Pkg-bazaar-commits mailing list