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