Rev 1: Put together a plugin to do the minimal work necessary in http://bzr.arbash-meinel.com/plugins/file_log
John Arbash Meinel
john at arbash-meinel.com
Thu Sep 18 16:15:04 BST 2008
At http://bzr.arbash-meinel.com/plugins/file_log
------------------------------------------------------------
revno: 1
revision-id: john at arbash-meinel.com-20080918151504-959o091bpv2kxfgn
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: file_log
timestamp: Thu 2008-09-18 10:15:04 -0500
message:
Put together a plugin to do the minimal work necessary
to make 'bzr log file' work and be fast.
-------------- next part --------------
=== added file '__init__.py'
--- a/__init__.py 1970-01-01 00:00:00 +0000
+++ b/__init__.py 2008-09-18 15:15:04 +0000
@@ -0,0 +1,75 @@
+# Copyright (C) 2008 Canonical Development 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
+
+"""Display the log for a single file."""
+
+from bzrlib import (
+ commands,
+ errors,
+ )
+
+class cmd_file_log(commands.Command):
+ """Show the log of a single file.
+
+ This is not quite the same as "bzr log file", as it only shows revisions
+ which modified the file, and not revisions which then merged those changes.
+ It also does not yet support revision ranges, etc.
+ """
+
+ takes_args = ['filename']
+ takes_options = ['log-format']
+
+ def run(self, filename, log_format=None):
+ import file_log
+ tree, relpath = WorkingTree.open_containing(filename)
+ tree.lock_read()
+ try:
+ file_id = tree.path2id(relpath)
+ if file_id is None:
+ raise BzrCommandError('"%s" is not a versioned file'
+ % (filename,))
+
+ # XXX: There should be a more direct way of just grabbing the
+ # last-modified revision from a tree
+ base_tree = tree.basis_tree()
+ base_tree.lock_read()
+ try:
+ if file_id not in base_tree.inventory:
+ raise BzrCommandError('"%s" is a newly added file'
+ % (filename,))
+ revision_id = base_tree.inventory[file_id].revision
+ finally:
+ base_tree.unlock()
+
+ if log_format is None:
+ log_format = log.log_formatter_registry.get_default(tree.branch)
+ lf = log_format(show_ids=False, to_file=self.outf,
+ show_timezone='original')
+ file_log.log_one_file(tree, file_id, revision_id, lf)
+ finally:
+ tree.unlock()
+
+commands.register_command(cmd_file_log)
+
+
+def load_tests(basic_tests, module, loader):
+ suite = loader.suiteClass()
+
+ test_files = [__name__ + '.' + x for x in [
+ '',
+ ]]
+ suite.addTests(loader.loadTestsFromModuleNames(test_files))
+ return suite
=== added file 'file_log.py'
--- a/file_log.py 1970-01-01 00:00:00 +0000
+++ b/file_log.py 2008-09-18 15:15:04 +0000
@@ -0,0 +1,62 @@
+# Copyright (C) 2008 Canonical Development 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
+
+"""Create a log for a single file."""
+
+from bzrlib import (
+ log,
+ errors,
+ )
+
+
+def log_one_file(tree, file_id, revision_id, log_formatter):
+ """Print out the revision graph for a single file.
+
+ :param tree: A WorkingTree with the given file_id present.
+ The tree should already be locked.
+ :param file_id: The file to log
+ :param revision_id: The tip revision to start from. Typically this is
+ tree.basis_tree().inventory[file_id].revision
+ :param log_formatter: An instance of LogFormatter, which we will use to
+ print out the revision information.
+ """
+ from bzrlib import graph
+
+ file_graph = graph.Graph(tree.branch.repository.texts)
+ tip_key = (file_id, revision_id)
+ # TODO: Topological sorting?
+ # file_ancestry = dict(file_graph.iter_ancestry([tip_key]))
+ # TODO: Remove nodes which are ghosts, and references to ghosts
+ # ghosts = set(key for key, parents in file_ancestry.iteritems()
+ # if parents is None)
+ # TODO: Batch up revision_ids to be logged to grab them multiples at a
+ # time.
+
+ # This iterates the per-file graph, and collects the revisions which are
+ # not considered ghosts.
+ # TODO: Use the whole-tree graph to compute dotted revnos, etc.
+ revisions = [(key[1], None, 0)
+ for key, parents in file_graph.iter_ancestry([tip_key])
+ if parents is not None]
+ revision_iterator = log.make_log_rev_iterator(tree.branch, revisions,
+ generate_delta=False,
+ search=None)
+ rev_tag_dict = {}
+ for revs in revision_iterator:
+ for (rev_id, revno, merge_depth), rev, delta in revs:
+ lr = LogRevision(rev, revno, merge_depth, delta,
+ rev_tag_dict.get(rev_id))
+ log_formatter.log_revision(lr)
More information about the bazaar-commits
mailing list