Rev 3505: Start implementing an API to give the status of individual files. in http://bzr.arbash-meinel.com/branches/bzr/1.6-dev/get_fingerprint

John Arbash Meinel john at arbash-meinel.com
Mon Jun 23 23:06:46 BST 2008


At http://bzr.arbash-meinel.com/branches/bzr/1.6-dev/get_fingerprint

------------------------------------------------------------
revno: 3505
revision-id: john at arbash-meinel.com-20080623220633-h3k0e8q0i4lsc5fn
parent: pqm at pqm.ubuntu.com-20080619070027-3xv1vy81m3ix2oup
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: get_fingerprint
timestamp: Mon 2008-06-23 17:06:33 -0500
message:
  Start implementing an API to give the status of individual files.
-------------- next part --------------
=== modified file 'bzrlib/tests/tree_implementations/__init__.py'
--- a/bzrlib/tests/tree_implementations/__init__.py	2008-04-30 20:09:39 +0000
+++ b/bzrlib/tests/tree_implementations/__init__.py	2008-06-23 22:06:33 +0000
@@ -349,6 +349,7 @@
     test_tree_implementations = [
         'bzrlib.tests.tree_implementations.test_annotate_iter',
         'bzrlib.tests.tree_implementations.test_get_file_mtime',
+        'bzrlib.tests.tree_implementations.test_get_fingerprint',
         'bzrlib.tests.tree_implementations.test_get_root_id',
         'bzrlib.tests.tree_implementations.test_get_symlink_target',
         'bzrlib.tests.tree_implementations.test_inv',

=== added file 'bzrlib/tests/tree_implementations/test_get_fingerprint.py'
--- a/bzrlib/tests/tree_implementations/test_get_fingerprint.py	1970-01-01 00:00:00 +0000
+++ b/bzrlib/tests/tree_implementations/test_get_fingerprint.py	2008-06-23 22:06:33 +0000
@@ -0,0 +1,73 @@
+# Copyright (C) 2008 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
+
+"""Test that all Tree's implement .get_fingerprint()"""
+
+from bzrlib.tests.tree_implementations import TestCaseWithTree
+
+
+class TestGetFingerprint(TestCaseWithTree):
+
+    def assertGetFingerprint(self, exp_kind, exp_modified, exp_info,
+                             tree, file_id, path=None, stat_value=None):
+        kind, modified, info = tree.get_fingerprint(file_id, path=path,
+                                                    stat_value=stat_value)
+        self.assertEqual(exp_kind, kind)
+        self.assertEqual(exp_modified, modified)
+        self.assertEqual(exp_info, info)
+
+    def test_directory(self):
+        wt = self.make_branch_and_tree('tree')
+        self.build_tree(['tree/dir/'])
+        wt.add(['dir'], ['dir-id'])
+        wt.commit('dir', rev_id='first-rev-id')
+        self.build_tree(['tree/dir2/'])
+        wt.add(['dir2'], ['dir2-id'])
+        wt.commit('dir2', rev_id='second-rev-id')
+
+        tree = self._convert_tree(wt)
+        tree.lock_read()
+        self.addCleanup(tree.unlock)
+        self.assertGetFingerprint('directory', 'first-rev-id', None,
+                                  tree, 'dir-id')
+        self.assertGetFingerprint('directory', 'second-rev-id', None,
+                                  tree, 'dir2-id')
+
+    def test_file_kind(self):
+        wt = self.make_branch_and_tree('tree')
+        self.build_tree(['tree/file'])
+        wt.add(['file'], ['file-id'])
+        wt.commit('file', rev_id='first-rev-id')
+        self.build_tree(['tree/file2'])
+        wt.add(['file2'], ['file2-id'])
+        wt.commit('file2', rev_id='second-rev-id')
+
+        tree = self._convert_tree(wt)
+        tree.lock_read()
+        self.addCleanup(tree.unlock)
+        self.assertGetFingerprint('file', 'first-rev-id',
+                                  'fdd68fdc095181052aaa4f74fdb2db4a2ce6eb9f',
+                                  tree, 'file-id')
+        self.assertGetFingerprint('file', 'second-rev-id',
+                                  '1ec597b46dd2dfa189ed8e9293c91bdccf55b45e',
+                                  tree, 'file2-id')
+
+    def test_missing(self):
+        wt = self.make_branch_and_tree('tree')
+        tree = self._convert_tree(wt)
+        tree.lock_read()
+        self.addCleanup(tree.unlock)
+        self.assertGetFingerprint(None, None, None, tree, 'no-such-file-id')

=== modified file 'bzrlib/tests/workingtree_implementations/__init__.py'
--- a/bzrlib/tests/workingtree_implementations/__init__.py	2008-04-28 08:57:45 +0000
+++ b/bzrlib/tests/workingtree_implementations/__init__.py	2008-06-23 22:06:33 +0000
@@ -103,6 +103,7 @@
         'bzrlib.tests.workingtree_implementations.test_executable',
         'bzrlib.tests.workingtree_implementations.test_flush',
         'bzrlib.tests.workingtree_implementations.test_get_file_mtime',
+        'bzrlib.tests.workingtree_implementations.test_get_fingerprint',
         'bzrlib.tests.workingtree_implementations.test_get_parent_ids',
         'bzrlib.tests.workingtree_implementations.test_inv',
         'bzrlib.tests.workingtree_implementations.test_is_control_filename',

=== added file 'bzrlib/tests/workingtree_implementations/test_get_fingerprint.py'
--- a/bzrlib/tests/workingtree_implementations/test_get_fingerprint.py	1970-01-01 00:00:00 +0000
+++ b/bzrlib/tests/workingtree_implementations/test_get_fingerprint.py	2008-06-23 22:06:33 +0000
@@ -0,0 +1,33 @@
+# Copyright (C) 2008 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
+
+"""Test that all WorkingTree's implement .get_fingerprint()"""
+
+from bzrlib.tests.workingtree_implementations import TestCaseWithWorkingTree
+from bzrlib.revision import CURRENT_REVISION
+
+
+class TestGetFingerprint(TestCaseWithWorkingTree):
+    """Working Trees should answer based on disk state."""
+
+    def assertGetFingerprint(self, exp_kind, exp_modified, exp_info,
+                             tree, file_id, path=None, stat_value=None):
+        kind, modified, info = tree.get_fingerprint(file_id, path=path,
+                                                    stat_value=stat_value)
+        self.assertEqual(exp_kind, kind)
+        self.assertEqual(exp_modified, modified)
+        self.assertEqual(exp_info, info)
+

=== modified file 'bzrlib/transform.py'
--- a/bzrlib/transform.py	2008-06-08 20:34:15 +0000
+++ b/bzrlib/transform.py	2008-06-23 22:06:33 +0000
@@ -1486,6 +1486,10 @@
     def get_file_sha1(self, file_id, path=None, stat_value=None):
         return self._transform._tree.get_file_sha1(file_id)
 
+    def get_fingerprint(self, file_id, path=None, stat_value=None):
+        return self._transform._tree.get_fingerprint(file_id, path=path,
+                stat_value=stat_value)
+
     def is_executable(self, file_id, path=None):
         return self._transform._tree.is_executable(file_id, path)
 

=== modified file 'bzrlib/tree.py'
--- a/bzrlib/tree.py	2008-05-08 04:33:38 +0000
+++ b/bzrlib/tree.py	2008-06-23 22:06:33 +0000
@@ -263,9 +263,47 @@
         """
         raise NotImplementedError(self.get_file_size)
 
+    def get_file_sha1(self, file_id, path=None, stat_value=None):
+        """Return the sha1 sum of the file.
+
+        :param file_id: The id for the file we are processing.
+        :param path: Optional relative path for the file.
+        :param stat_value: Optional stat value to use for freshness check.
+        """
+        raise NotImplementedError(self.get_file_sha1)
+
     def get_file_by_path(self, path):
         return self.get_file(self._inventory.path2id(path), path)
 
+    def get_fingerprint(self, file_id, path=None, stat_value=None):
+        """Return the revision_id where this object was last modified.
+        
+        :param file_id: The file in question
+        :param path: An optional hint as to where this can be located
+        :param stat_value: For working trees, you can pass in a known stat
+            value.
+        :return: (kind, last_modified_revision_id, info) For directories,
+            info will be None, for symlinks it will be the symlink
+            target and for files it will be the sha1sum.
+            If the object is not present, this will return (None, None, None)
+        """
+        """See Tree.get_fingerprint"""
+        try:
+            ie = self.inventory[file_id]
+        except errors.NoSuchId:
+            return None, None, None
+        kind = ie.kind
+        if kind == 'directory':
+            info = None
+        elif kind == 'symlink':
+            info = ie.symlink_target
+        else:
+            assert kind == 'file'
+            info = ie.text_sha1
+        last_modified = ie.revision
+        return (kind, last_modified, info)
+
+
     def iter_files_bytes(self, desired_files):
         """Iterate through file contents.
 

=== modified file 'bzrlib/workingtree.py'
--- a/bzrlib/workingtree.py	2008-06-02 16:09:09 +0000
+++ b/bzrlib/workingtree.py	2008-06-23 22:06:33 +0000
@@ -569,6 +569,73 @@
             path = self._inventory.id2path(file_id)
         return self._hashcache.get_sha1(path, stat_value)
 
+    def get_fingerprint(self, file_id, path=None, stat_value=None):
+        """See Tree.get_fingerprint()"""
+        try:
+            ie = self.inventory[file_id]
+        except errors.NoSuchId:
+            return None, None, None
+
+        if path is None:
+            path = self._inventory.id2path(file_id)
+        abspath = self.abspath(path)
+        if stat_value is None:
+            try:
+                stat_value = os.lstat(abspath)
+            except OSError, e:
+                if e.errno == errno.ENOENT:
+                    return None, None, None
+                else:
+                    raise
+        kind = osutils.file_kind_from_stat_mode(stat_value.st_mode)
+        if kind == 'file':
+            info = self.get_file_sha1(file_id, path=path,
+                                      stat_value=stat_value)
+        elif kind == 'directory':
+            info = None
+        elif kind == 'symlink':
+            info = os.readlink(abspath)
+
+        num_parents = len(self.get_parent_ids())
+        if num_parents == 0: # No basis, everything is new
+            return (kind, _mod_revision.CURRENT_REVISION, info)
+        elif num_parents > 1:
+            # Not implemented yet
+            raise NotImplementedError
+        else:
+            # XXX: We *really* DO NOT want to be creating a new basis_tree for
+            #      every query into this function.
+            # Check to see if this is modified relative to base
+            basis_tree = self.basis_tree()
+            basis_tree.lock_read()
+            try:
+                # Now we have enough to know the current state, we need to compare
+                # against the basis to know last_modified
+                try:
+                    basis_ie = basis_tree.inventory[file_id]
+                except errors.NoSuchId:
+                    # This didn't exist in the base, so it gets marked current
+                    is_modified = True
+                else:
+                    basis_relpath = basis_tree.id2path(file_id)
+                    if basis_ie.kind != kind or basis_relpath != path:
+                        is_modified = True
+                    else:
+                        if kind == 'file':
+                            is_modified = (info != basis_ie.text_sha1)
+                        elif kind == 'directory':
+                            is_modified = False
+                        elif kind == 'symlink':
+                            is_modified = (info != basis_ie.symlink_target)
+                        else:
+                            raise AssertionError('Unknown kind: %s' % (kind,))
+                if is_modified:
+                    return (kind, _mod_revision.CURRENT_REVISION, info)
+                else:
+                    return (kind, basis_ie.revision, info)
+            finally:
+                basis_tree.unlock()
+
     def get_file_mtime(self, file_id, path=None):
         if not path:
             path = self.inventory.id2path(file_id)

=== modified file 'bzrlib/workingtree_4.py'
--- a/bzrlib/workingtree_4.py	2008-06-06 16:40:46 +0000
+++ b/bzrlib/workingtree_4.py	2008-06-23 22:06:33 +0000
@@ -414,6 +414,36 @@
             return link_or_sha1
         return None
 
+    #def get_fingerprint(self, file_id, path=None, stat_value=None):
+    #    """See Tree.get_fingerprint()"""
+    #    entry = self._get_entry(file_id=file_id, path=path)
+    #    if entry[0] is None:
+    #        return None, None, None
+    #    if path is None:
+    #        path = pathjoin(entry[0][0], entry[0][1]).decode('utf8')
+
+    #    state = self.current_dirstate()
+    #    file_abspath = self.abspath(path)
+    #    if stat_value is None:
+    #        try:
+    #            stat_value = os.lstat(file_abspath)
+    #        except OSError, e:
+    #            if e.errno == errno.ENOENT:
+    #                return None
+    #            else:
+    #                raise
+    #    link_or_sha1 = state.update_entry(entry, file_abspath,
+    #                                      stat_value=stat_value)
+    #    minikind = entry[1][0][0]
+    #    kind = dirstate.DirState._minikind_to_kind[minikind]
+    #    num_parents = len(state.get_parent_ids())
+    #    if num_parents == 0: # No parents == modified
+    #        last_modified = _mod_revision.CURRENT_REVISION
+    #    elif num_parents == 1: # Compare to the first parent only
+    #        import pdb; pdb.set_trace()
+    #        # XXX: Implement for comparing against 1 or > 1 parents
+    #    return None
+
     def _get_inventory(self):
         """Get the inventory for the tree. This is only valid within a lock."""
         if 'evil' in debug.debug_flags:



More information about the bazaar-commits mailing list