[Pkg-bazaar-commits] ./bzr/unstable r453: - Split WorkingTree into its own file

Martin Pool mbp at sourcefrog.net
Fri Apr 10 08:19:27 UTC 2009


------------------------------------------------------------
revno: 453
committer: Martin Pool <mbp at sourcefrog.net>
timestamp: Wed 2005-05-11 12:22:26 +1000
message:
  - Split WorkingTree into its own file
  - pychecker fixes
  - statcache works in terms of just directories, not branches
  - use statcache from workingtree when getting file SHA-1 so that 
    diffs are faster
added:
  bzrlib/workingtree.py
modified:
  TODO
  bzrlib/branch.py
  bzrlib/commands.py
  bzrlib/statcache.py
  bzrlib/tree.py
-------------- next part --------------
=== modified file 'TODO'
--- a/TODO	2005-05-11 01:09:41 +0000
+++ b/TODO	2005-05-11 02:22:26 +0000
@@ -225,7 +225,7 @@
 
   - Hold the ElementTree in memory in the Inventory object and work
     directly on that, rather than converting into Python objects every
-    time it is read in.  Probably still expose it through some kind of
+    time it is read in.  Probably still exposoe it through some kind of
     object interface though, but perhaps that should just be a proxy
     for the elements.
 
@@ -246,6 +246,8 @@
   urlgrabber's docs say they are working on batched downloads; we
   could perhaps ride on that or just create a background thread (ew).
 
+* Should be a signature at the top of the cache file.
+
 
 Large things
 ------------

=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py	2005-05-10 06:09:58 +0000
+++ b/bzrlib/branch.py	2005-05-11 02:22:26 +0000
@@ -24,7 +24,7 @@
 import bzrlib
 from inventory import Inventory
 from trace import mutter, note
-from tree import Tree, EmptyTree, RevisionTree, WorkingTree
+from tree import Tree, EmptyTree, RevisionTree
 from inventory import InventoryEntry, Inventory
 from osutils import isdir, quotefn, isfile, uuid, sha_file, username, \
      format_date, compact_date, pumpfile, user_email, rand_bytes, splitpath, \
@@ -785,6 +785,7 @@
 
     def working_tree(self):
         """Return a `Tree` for the working copy."""
+        from workingtree import WorkingTree
         return WorkingTree(self.base, self.read_working_inventory())
 
 

=== modified file 'bzrlib/commands.py'
--- a/bzrlib/commands.py	2005-05-11 00:56:49 +0000
+++ b/bzrlib/commands.py	2005-05-11 02:22:26 +0000
@@ -23,7 +23,7 @@
 from bzrlib.trace import mutter, note, log_error
 from bzrlib.errors import bailout, BzrError, BzrCheckError, BzrCommandError
 from bzrlib.osutils import quotefn, pumpfile, isdir, isfile
-from bzrlib.tree import RevisionTree, EmptyTree, WorkingTree, Tree
+from bzrlib.tree import RevisionTree, EmptyTree, Tree
 from bzrlib.revision import Revision
 from bzrlib import Branch, Inventory, InventoryEntry, ScratchBranch, BZRDIR, \
      format_date

=== modified file 'bzrlib/statcache.py'
--- a/bzrlib/statcache.py	2005-05-10 06:54:12 +0000
+++ b/bzrlib/statcache.py	2005-05-11 02:22:26 +0000
@@ -82,10 +82,11 @@
             fs.st_ctime, fs.st_ino, fs.st_dev)
 
 
-def _write_cache(branch, entry_iter, dangerfiles):
+def _write_cache(basedir, entry_iter, dangerfiles):
     from atomicfile import AtomicFile
-    
-    outf = AtomicFile(branch.controlfilename('stat-cache'), 'wb', 'utf-8')
+
+    cachefn = os.path.join(basedir, '.bzr', 'stat-cache')
+    outf = AtomicFile(cachefn, 'wb', 'utf-8')
     try:
         for entry in entry_iter:
             if entry[0] in dangerfiles:
@@ -100,11 +101,14 @@
             outf.abort()
         
         
-def load_cache(branch):
+def load_cache(basedir):
+    import codecs
+    
     cache = {}
 
     try:
-        cachefile = branch.controlfile('stat-cache', 'r')
+        cachefn = os.path.join(basedir, '.bzr', 'stat-cache')
+        cachefile = codecs.open(cachefn, 'r', 'utf-8')
     except IOError:
         return cache
     
@@ -127,7 +131,7 @@
     
 
 
-def update_cache(branch, inv=None, flush=False):
+def update_cache(basedir, inv, flush=False):
     """Update and return the cache for the branch.
 
     The returned cache may contain entries that have not been written
@@ -145,14 +149,12 @@
     if flush:
         cache = {}
     else:
-        cache = load_cache(branch)
-    if inv == None:
-        inv = branch.read_working_inventory()
-    return _update_cache_from_list(branch, cache, _files_from_inventory(inv))
-
-
-
-def _update_cache_from_list(branch, cache, to_update):
+        cache = load_cache(basedir)
+    return _update_cache_from_list(basedir, cache, _files_from_inventory(inv))
+
+
+
+def _update_cache_from_list(basedir, cache, to_update):
     """Update and return the cache for given files.
 
     cache -- Previously cached values to be validated.
@@ -171,7 +173,7 @@
     now = int(time.time())
     
     for file_id, path in to_update:
-        fap = branch.abspath(path)
+        fap = os.path.join(basedir, path)
         fp = fingerprint(fap, path)
         cacheentry = cache.get(file_id)
 
@@ -204,6 +206,6 @@
         
     if dirty:
         mutter('updating on-disk statcache')
-        _write_cache(branch, cache.itervalues(), dangerfiles)
+        _write_cache(basedir, cache.itervalues(), dangerfiles)
 
     return cache

=== modified file 'bzrlib/tree.py'
--- a/bzrlib/tree.py	2005-04-15 07:53:59 +0000
+++ b/bzrlib/tree.py	2005-05-11 02:22:26 +0000
@@ -121,229 +121,11 @@
             elif kind == 'file':
                 pumpfile(self.get_file(ie.file_id), file(fullpath, 'wb'))
             else:
-                bailout("don't know how to export {%s} of kind %r" % (fid, kind))
+                bailout("don't know how to export {%s} of kind %r" % (ie.file_id, kind))
             mutter("  export {%s} kind %s to %s" % (ie.file_id, kind, fullpath))
 
 
 
-class WorkingTree(Tree):
-    """Working copy tree.
-
-    The inventory is held in the `Branch` working-inventory, and the
-    files are in a directory on disk.
-
-    It is possible for a `WorkingTree` to have a filename which is
-    not listed in the Inventory and vice versa.
-    """
-    def __init__(self, basedir, inv):
-        self._inventory = inv
-        self.basedir = basedir
-        self.path2id = inv.path2id
-
-    def __repr__(self):
-        return "<%s of %s>" % (self.__class__.__name__,
-                               self.basedir)
-
-    def abspath(self, filename):
-        return os.path.join(self.basedir, filename)
-
-    def has_filename(self, filename):
-        return os.path.exists(self.abspath(filename))
-
-    def get_file(self, file_id):
-        return self.get_file_byname(self.id2path(file_id))
-
-    def get_file_byname(self, filename):
-        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):
-        # files that have been deleted are excluded
-        if not self.inventory.has_id(file_id):
-            return False
-        return os.access(self.abspath(self.inventory.id2path(file_id)), os.F_OK)
-
-    def get_file_size(self, file_id):
-        return os.stat(self._get_store_filename(file_id))[ST_SIZE]
-
-    def get_file_sha1(self, file_id):
-        f = self.get_file(file_id)
-        return sha_file(f)
-
-
-    def file_class(self, filename):
-        if self.path2id(filename):
-            return 'V'
-        elif self.is_ignored(filename):
-            return 'I'
-        else:
-            return '?'
-
-
-    def list_files(self):
-        """Recursively list all files as (path, class, kind, id).
-
-        Lists, but does not descend into unversioned directories.
-
-        This does not include files that have been deleted in this
-        tree.
-
-        Skips the control directory.
-        """
-        inv = self.inventory
-
-        def descend(from_dir_relpath, from_dir_id, dp):
-            ls = os.listdir(dp)
-            ls.sort()
-            for f in ls:
-                ## TODO: If we find a subdirectory with its own .bzr
-                ## directory, then that is a separate tree and we
-                ## should exclude it.
-                if bzrlib.BZRDIR == f:
-                    continue
-
-                # path within tree
-                fp = appendpath(from_dir_relpath, f)
-
-                # absolute path
-                fap = appendpath(dp, f)
-                
-                f_ie = inv.get_child(from_dir_id, f)
-                if f_ie:
-                    c = 'V'
-                elif self.is_ignored(fp):
-                    c = 'I'
-                else:
-                    c = '?'
-
-                fk = file_kind(fap)
-
-                if f_ie:
-                    if f_ie.kind != fk:
-                        bailout("file %r entered as kind %r id %r, now of kind %r"
-                                % (fap, f_ie.kind, f_ie.file_id, fk))
-
-                yield fp, c, fk, (f_ie and f_ie.file_id)
-
-                if fk != 'directory':
-                    continue
-
-                if c != 'V':
-                    # don't descend unversioned directories
-                    continue
-                
-                for ff in descend(fp, f_ie.file_id, fap):
-                    yield ff
-
-        for f in descend('', inv.root.file_id, self.basedir):
-            yield f
-            
-
-
-    def unknowns(self):
-        for subp in self.extras():
-            if not self.is_ignored(subp):
-                yield subp
-
-
-    def extras(self):
-        """Yield all unknown files in this WorkingTree.
-
-        If there are any unknown directories then only the directory is
-        returned, not all its children.  But if there are unknown files
-        under a versioned subdirectory, they are returned.
-
-        Currently returned depth-first, sorted by name within directories.
-        """
-        ## TODO: Work from given directory downwards
-        
-        for path, dir_entry in self.inventory.directories():
-            mutter("search for unknowns in %r" % path)
-            dirabs = self.abspath(path)
-            if not isdir(dirabs):
-                # e.g. directory deleted
-                continue
-
-            fl = []
-            for subf in os.listdir(dirabs):
-                if (subf != '.bzr'
-                    and (subf not in dir_entry.children)):
-                    fl.append(subf)
-            
-            fl.sort()
-            for subf in fl:
-                subp = appendpath(path, subf)
-                yield subp
-
-
-    def ignored_files(self):
-        """Yield list of PATH, IGNORE_PATTERN"""
-        for subp in self.extras():
-            pat = self.is_ignored(subp)
-            if pat != None:
-                yield subp, pat
-
-
-    def get_ignore_list(self):
-        """Return list of ignore patterns.
-
-        Cached in the Tree object after the first call.
-        """
-        if hasattr(self, '_ignorelist'):
-            return self._ignorelist
-
-        l = bzrlib.DEFAULT_IGNORE[:]
-        if self.has_filename(bzrlib.IGNORE_FILENAME):
-            f = self.get_file_byname(bzrlib.IGNORE_FILENAME)
-            l.extend([line.rstrip("\n\r") for line in f.readlines()])
-        self._ignorelist = l
-        return l
-
-
-    def is_ignored(self, filename):
-        r"""Check whether the filename matches an ignore pattern.
-
-        Patterns containing '/' or '\' need to match the whole path;
-        others match against only the last component.
-
-        If the file is ignored, returns the pattern which caused it to
-        be ignored, otherwise None.  So this can simply be used as a
-        boolean if desired."""
-
-        # TODO: Use '**' to match directories, and other extended
-        # globbing stuff from cvs/rsync.
-
-        # XXX: fnmatch is actually not quite what we want: it's only
-        # approximately the same as real Unix fnmatch, and doesn't
-        # treat dotfiles correctly and allows * to match /.
-        # Eventually it should be replaced with something more
-        # accurate.
-        
-        for pat in self.get_ignore_list():
-            if '/' in pat or '\\' in pat:
-                
-                # as a special case, you can put ./ at the start of a
-                # pattern; this is good to match in the top-level
-                # only;
-                
-                if (pat[:2] == './') or (pat[:2] == '.\\'):
-                    newpat = pat[2:]
-                else:
-                    newpat = pat
-                if fnmatch.fnmatchcase(filename, newpat):
-                    return pat
-            else:
-                if fnmatch.fnmatchcase(splitpath(filename)[-1], pat):
-                    return pat
-        return None
-        
-
-        
-        
-
 class RevisionTree(Tree):
     """Tree viewing a previous revision.
 

=== added file 'bzrlib/workingtree.py'
--- a/bzrlib/workingtree.py	1970-01-01 00:00:00 +0000
+++ b/bzrlib/workingtree.py	2005-05-11 02:22:26 +0000
@@ -0,0 +1,259 @@
+# 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 os
+    
+import bzrlib.tree
+from errors import BzrCheckError
+from trace import mutter
+
+
+class WorkingTree(bzrlib.tree.Tree):
+    """Working copy tree.
+
+    The inventory is held in the `Branch` working-inventory, and the
+    files are in a directory on disk.
+
+    It is possible for a `WorkingTree` to have a filename which is
+    not listed in the Inventory and vice versa.
+    """
+    _statcache = None
+    
+    def __init__(self, basedir, inv):
+        self._inventory = inv
+        self.basedir = basedir
+        self.path2id = inv.path2id
+
+    def __repr__(self):
+        return "<%s of %s>" % (self.__class__.__name__,
+                               self.basedir)
+
+    def abspath(self, filename):
+        return os.path.join(self.basedir, filename)
+
+    def has_filename(self, filename):
+        return os.path.exists(self.abspath(filename))
+
+    def get_file(self, file_id):
+        return self.get_file_byname(self.id2path(file_id))
+
+    def get_file_byname(self, filename):
+        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):
+        # files that have been deleted are excluded
+        if not self.inventory.has_id(file_id):
+            return False
+        import os
+        return os.access(self.abspath(self.inventory.id2path(file_id)), os.F_OK)
+
+    def get_file_size(self, file_id):
+        import os, stat
+        return os.stat(self._get_store_filename(file_id))[stat.ST_SIZE]
+
+
+    def get_file_sha1(self, file_id):
+        import statcache
+        if not self._statcache:
+            self._statcache = statcache.update_cache(self.basedir, self.inventory)
+
+        return self._statcache[file_id][statcache.SC_SHA1]
+
+
+    def file_class(self, filename):
+        if self.path2id(filename):
+            return 'V'
+        elif self.is_ignored(filename):
+            return 'I'
+        else:
+            return '?'
+
+
+    def list_files(self):
+        """Recursively list all files as (path, class, kind, id).
+
+        Lists, but does not descend into unversioned directories.
+
+        This does not include files that have been deleted in this
+        tree.
+
+        Skips the control directory.
+        """
+        from osutils import appendpath, file_kind
+        import os
+
+        inv = self.inventory
+
+        def descend(from_dir_relpath, from_dir_id, dp):
+            ls = os.listdir(dp)
+            ls.sort()
+            for f in ls:
+                ## TODO: If we find a subdirectory with its own .bzr
+                ## directory, then that is a separate tree and we
+                ## should exclude it.
+                if bzrlib.BZRDIR == f:
+                    continue
+
+                # path within tree
+                fp = appendpath(from_dir_relpath, f)
+
+                # absolute path
+                fap = appendpath(dp, f)
+                
+                f_ie = inv.get_child(from_dir_id, f)
+                if f_ie:
+                    c = 'V'
+                elif self.is_ignored(fp):
+                    c = 'I'
+                else:
+                    c = '?'
+
+                fk = file_kind(fap)
+
+                if f_ie:
+                    if f_ie.kind != fk:
+                        raise BzrCheckError("file %r entered as kind %r id %r, "
+                                            "now of kind %r"
+                                            % (fap, f_ie.kind, f_ie.file_id, fk))
+
+                yield fp, c, fk, (f_ie and f_ie.file_id)
+
+                if fk != 'directory':
+                    continue
+
+                if c != 'V':
+                    # don't descend unversioned directories
+                    continue
+                
+                for ff in descend(fp, f_ie.file_id, fap):
+                    yield ff
+
+        for f in descend('', inv.root.file_id, self.basedir):
+            yield f
+            
+
+
+    def unknowns(self):
+        for subp in self.extras():
+            if not self.is_ignored(subp):
+                yield subp
+
+
+    def extras(self):
+        """Yield all unknown files in this WorkingTree.
+
+        If there are any unknown directories then only the directory is
+        returned, not all its children.  But if there are unknown files
+        under a versioned subdirectory, they are returned.
+
+        Currently returned depth-first, sorted by name within directories.
+        """
+        ## TODO: Work from given directory downwards
+        from osutils import isdir, appendpath
+        
+        for path, dir_entry in self.inventory.directories():
+            mutter("search for unknowns in %r" % path)
+            dirabs = self.abspath(path)
+            if not isdir(dirabs):
+                # e.g. directory deleted
+                continue
+
+            fl = []
+            for subf in os.listdir(dirabs):
+                if (subf != '.bzr'
+                    and (subf not in dir_entry.children)):
+                    fl.append(subf)
+            
+            fl.sort()
+            for subf in fl:
+                subp = appendpath(path, subf)
+                yield subp
+
+
+    def ignored_files(self):
+        """Yield list of PATH, IGNORE_PATTERN"""
+        for subp in self.extras():
+            pat = self.is_ignored(subp)
+            if pat != None:
+                yield subp, pat
+
+
+    def get_ignore_list(self):
+        """Return list of ignore patterns.
+
+        Cached in the Tree object after the first call.
+        """
+        if hasattr(self, '_ignorelist'):
+            return self._ignorelist
+
+        l = bzrlib.DEFAULT_IGNORE[:]
+        if self.has_filename(bzrlib.IGNORE_FILENAME):
+            f = self.get_file_byname(bzrlib.IGNORE_FILENAME)
+            l.extend([line.rstrip("\n\r") for line in f.readlines()])
+        self._ignorelist = l
+        return l
+
+
+    def is_ignored(self, filename):
+        r"""Check whether the filename matches an ignore pattern.
+
+        Patterns containing '/' or '\' need to match the whole path;
+        others match against only the last component.
+
+        If the file is ignored, returns the pattern which caused it to
+        be ignored, otherwise None.  So this can simply be used as a
+        boolean if desired."""
+
+        # TODO: Use '**' to match directories, and other extended
+        # globbing stuff from cvs/rsync.
+
+        # XXX: fnmatch is actually not quite what we want: it's only
+        # approximately the same as real Unix fnmatch, and doesn't
+        # treat dotfiles correctly and allows * to match /.
+        # Eventually it should be replaced with something more
+        # accurate.
+        
+        import fnmatch
+        from osutils import splitpath
+        
+        for pat in self.get_ignore_list():
+            if '/' in pat or '\\' in pat:
+                
+                # as a special case, you can put ./ at the start of a
+                # pattern; this is good to match in the top-level
+                # only;
+                
+                if (pat[:2] == './') or (pat[:2] == '.\\'):
+                    newpat = pat[2:]
+                else:
+                    newpat = pat
+                if fnmatch.fnmatchcase(filename, newpat):
+                    return pat
+            else:
+                if fnmatch.fnmatchcase(splitpath(filename)[-1], pat):
+                    return pat
+        else:
+            return None
+        
+
+        
+        
+



More information about the Pkg-bazaar-commits mailing list