Rev 3145: Implement native support for --using (abentley) in file:///home/pqm/archives/thelove/bzr/%2Btrunk/
Canonical.com Patch Queue Manager
pqm at pqm.ubuntu.com
Thu Dec 27 15:01:55 GMT 2007
At file:///home/pqm/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 3145
revision-id:pqm at pqm.ubuntu.com-20071227150146-08nqv2gvo5e3i1n3
parent: pqm at pqm.ubuntu.com-20071222080058-lra6luc153ex60w4
parent: aaron.bentley at utoronto.ca-20071227022814-e1ance6116xmbmqk
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Thu 2007-12-27 15:01:46 +0000
message:
Implement native support for --using (abentley)
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/builtins.py builtins.py-20050830033751-fc01482b9ca23183
bzrlib/commands.py bzr.py-20050309040720-d10f4714595cf8c3
bzrlib/diff.py diff.py-20050309040759-26944fbbf2ebbf36
bzrlib/tests/test_diff.py testdiff.py-20050727164403-d1a3496ebb12e339
------------------------------------------------------------
revno: 3123.4.1.1.3
revision-id:aaron.bentley at utoronto.ca-20071227022814-e1ance6116xmbmqk
parent: aaron.bentley at utoronto.ca-20071226211353-zum7avm4gfgyfwam
committer: Aaron Bentley <aaron.bentley at utoronto.ca>
branch nick: no-inventory2
timestamp: Wed 2007-12-26 21:28:14 -0500
message:
Fix typo
modified:
bzrlib/commands.py bzr.py-20050309040720-d10f4714595cf8c3
------------------------------------------------------------
revno: 3123.4.1.1.2
revision-id:aaron.bentley at utoronto.ca-20071226211353-zum7avm4gfgyfwam
parent: aaron.bentley at utoronto.ca-20071226033623-5wgrblepj4dqlw6r
committer: Aaron Bentley <aaron.bentley at utoronto.ca>
branch nick: no-inventory2
timestamp: Wed 2007-12-26 16:13:53 -0500
message:
Implement diff --using natively
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/builtins.py builtins.py-20050830033751-fc01482b9ca23183
bzrlib/commands.py bzr.py-20050309040720-d10f4714595cf8c3
bzrlib/diff.py diff.py-20050309040759-26944fbbf2ebbf36
bzrlib/tests/test_diff.py testdiff.py-20050727164403-d1a3496ebb12e339
------------------------------------------------------------
revno: 3123.4.1.1.1
revision-id:aaron.bentley at utoronto.ca-20071226033623-5wgrblepj4dqlw6r
parent: aaron.bentley at utoronto.ca-20071218041534-w9spqi20zck44bvd
parent: pqm at pqm.ubuntu.com-20071222080058-lra6luc153ex60w4
committer: Aaron Bentley <aaron.bentley at utoronto.ca>
branch nick: no-inventory2
timestamp: Tue 2007-12-25 22:36:23 -0500
message:
Merge from bzr.dev
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/_patiencediff_c.c _patiencediff_c.c-20070721205602-q3imkipwlgagp3cy-1
bzrlib/branch.py branch.py-20050309040759-e4baf4e0d046576e
bzrlib/builtins.py builtins.py-20050830033751-fc01482b9ca23183
bzrlib/bundle/serializer/v4.py v10.py-20070611062757-5ggj7k18s9dej0fr-1
bzrlib/bzrdir.py bzrdir.py-20060131065624-156dfea39c4387cb
bzrlib/commit.py commit.py-20050511101309-79ec1a0168e0e825
bzrlib/diff.py diff.py-20050309040759-26944fbbf2ebbf36
bzrlib/dirstate.py dirstate.py-20060728012006-d6mvoihjb3je9peu-1
bzrlib/errors.py errors.py-20050309040759-20512168c4e14fbd
bzrlib/graph.py graph_walker.py-20070525030359-y852guab65d4wtn0-1
bzrlib/index.py index.py-20070712131115-lolkarso50vjr64s-1
bzrlib/inventory.py inventory.py-20050309040759-6648b84ca2005b37
bzrlib/merge.py merge.py-20050513021216-953b65a438527106
bzrlib/osutils.py osutils.py-20050309040759-eeaff12fbf77ac86
bzrlib/remote.py remote.py-20060720103555-yeeg2x51vn0rbtdp-1
bzrlib/repofmt/knitrepo.py knitrepo.py-20070206081537-pyy4a00xdas0j4pf-1
bzrlib/repofmt/pack_repo.py pack_repo.py-20070813041115-gjv5ma7ktfqwsjgn-1
bzrlib/repository.py rev_storage.py-20051111201905-119e9401e46257e3
bzrlib/revision.py revision.py-20050309040759-e77802c08f3999d5
bzrlib/smart/medium.py medium.py-20061103051856-rgu2huy59fkz902q-1
bzrlib/symbol_versioning.py symbol_versioning.py-20060105104851-9ecf8af605d15a80
bzrlib/tests/TestUtil.py TestUtil.py-20050824080200-5f70140a2d938694
bzrlib/tests/__init__.py selftest.py-20050531073622-8d0e3c8845c97a64
bzrlib/tests/blackbox/test_checkout.py test_checkout.py-20060211231752-a5cde67cf70af854
bzrlib/tests/blackbox/test_merge.py test_merge.py-20060323225809-9bc0459c19917f41
bzrlib/tests/blackbox/test_non_ascii.py test_non_ascii.py-20060105214030-68010be784a5d854
bzrlib/tests/blackbox/test_split.py test_split.py-20061008023421-qy0vdpzysh5rriu8-1
bzrlib/tests/bzrdir_implementations/test_bzrdir.py test_bzrdir.py-20060131065642-0ebeca5e30e30866
bzrlib/tests/repository_implementations/__init__.py __init__.py-20060131092037-9564957a7d4a841b
bzrlib/tests/repository_implementations/test_repository.py test_repository.py-20060131092128-ad07f494f5c9d26c
bzrlib/tests/test_ancestry.py test_ancestry.py-20050913023709-69768e94848312c6
bzrlib/tests/test_bzrdir.py test_bzrdir.py-20060131065654-deba40eef51cf220
bzrlib/tests/test_commit.py test_commit.py-20050914060732-279f057f8c295434
bzrlib/tests/test_diff.py testdiff.py-20050727164403-d1a3496ebb12e339
bzrlib/tests/test_extract.py test_extract.py-20061002214140-qdnnm67q1ov6x6pd-1
bzrlib/tests/test_graph.py test_graph_walker.py-20070525030405-enq4r60hhi9xrujc-1
bzrlib/tests/test_http.py testhttp.py-20051018020158-b2eef6e867c514d9
bzrlib/tests/test_merge.py testmerge.py-20050905070950-c1b5aa49ff911024
bzrlib/tests/test_msgeditor.py test_msgeditor.py-20051202041359-920315ec6011ee51
bzrlib/tests/test_revision.py testrevision.py-20050804210559-46f5e1eb67b01289
bzrlib/tests/test_selftest.py test_selftest.py-20051202044319-c110a115d8c0456a
bzrlib/tests/test_transform.py test_transaction.py-20060105172520-b3ffb3946550e6c4
bzrlib/tests/test_version_info.py test_version_info.py-20051228204928-2c364e30b702b41b
bzrlib/tests/test_workingtree.py testworkingtree.py-20051004024258-b88d0fe8f101d468
bzrlib/tests/tree_implementations/test_inv.py test_inv.py-20070312023226-0cdvk5uwhutis9vg-1
bzrlib/transform.py transform.py-20060105172343-dd99e54394d91687
bzrlib/transport/http/__init__.py http_transport.py-20050711212304-506c5fd1059ace96
bzrlib/transport/http/_pycurl.py pycurlhttp.py-20060110060940-4e2a705911af77a6
bzrlib/transport/http/_urllib.py _urlgrabber.py-20060113083826-0bbf7d992fbf090c
bzrlib/transport/http/_urllib2_wrappers.py _urllib2_wrappers.py-20060913231729-ha9ugi48ktx481ao-1
bzrlib/tree.py tree.py-20050309040759-9d5f2496be663e77
bzrlib/version_info_formats/__init__.py generate_version_info.py-20051228204928-8358edabcddcd97e
bzrlib/versionedfile.py versionedfile.py-20060222045106-5039c71ee3b65490
bzrlib/workingtree.py workingtree.py-20050511021032-29b6ec0a681e02e3
bzrlib/workingtree_4.py workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
=== modified file 'NEWS'
--- a/NEWS 2007-12-22 08:00:58 +0000
+++ b/NEWS 2007-12-26 21:13:53 +0000
@@ -19,6 +19,9 @@
* New option to use custom template-based formats in ``bzr version-info``.
(Lukáš Lalinský)
+ * diff '--using' allows an external diff tool to be used for files.
+ (Aaron Bentley)
+
IMPROVEMENTS:
* ``branch`` and ``checkout`` can now use files from a working tree to
=== modified file 'bzrlib/builtins.py'
--- a/bzrlib/builtins.py 2007-12-21 05:52:38 +0000
+++ b/bzrlib/builtins.py 2007-12-26 21:13:53 +0000
@@ -1454,17 +1454,6 @@
bzr diff --prefix old/:new/
"""
- # TODO: Option to use external diff command; could be GNU diff, wdiff,
- # or a graphical diff.
-
- # TODO: Python difflib is not exactly the same as unidiff; should
- # either fix it up or prefer to use an external diff.
-
- # TODO: Selected-file diff is inefficient and doesn't show you
- # deleted files.
-
- # TODO: This probably handles non-Unix newlines poorly.
-
_see_also = ['status']
takes_args = ['file*']
takes_options = [
@@ -1484,13 +1473,17 @@
),
'revision',
'change',
+ Option('using',
+ help='Use this command to compare files.',
+ type=unicode,
+ ),
]
aliases = ['di', 'dif']
encoding_type = 'exact'
@display_command
def run(self, revision=None, file_list=None, diff_options=None,
- prefix=None, old=None, new=None):
+ prefix=None, old=None, new=None, using=None):
from bzrlib.diff import _get_trees_to_diff, show_diff_trees
if (prefix is None) or (prefix == '0'):
@@ -1517,7 +1510,7 @@
specific_files=specific_files,
external_diff_options=diff_options,
old_label=old_label, new_label=new_label,
- extra_trees=extra_trees)
+ extra_trees=extra_trees, using=using)
class cmd_deleted(Command):
=== modified file 'bzrlib/commands.py'
--- a/bzrlib/commands.py 2007-09-24 06:42:21 +0000
+++ b/bzrlib/commands.py 2007-12-27 02:28:14 +0000
@@ -627,6 +627,11 @@
return ret
+def shlex_split_unicode(unsplit):
+ import shlex
+ return [u.decode('utf-8') for u in shlex.split(unsplit.encode('utf-8'))]
+
+
def get_alias(cmd, config=None):
"""Return an expanded alias, or None if no alias exists.
@@ -642,8 +647,7 @@
config = bzrlib.config.GlobalConfig()
alias = config.get_alias(cmd)
if (alias):
- import shlex
- return [a.decode('utf-8') for a in shlex.split(alias.encode('utf-8'))]
+ return shlex_split_unicode(alias)
return None
=== modified file 'bzrlib/diff.py'
--- a/bzrlib/diff.py 2007-12-19 21:17:25 +0000
+++ b/bzrlib/diff.py 2007-12-26 21:13:53 +0000
@@ -17,6 +17,7 @@
import difflib
import os
import re
+import shutil
import sys
from bzrlib.lazy_import import lazy_import
@@ -28,6 +29,7 @@
from bzrlib import (
bzrdir,
+ commands,
errors,
osutils,
patiencediff,
@@ -467,7 +469,8 @@
external_diff_options=None,
old_label='a/', new_label='b/',
extra_trees=None,
- path_encoding='utf8'):
+ path_encoding='utf8',
+ using=None):
"""Show in text form the changes from one tree to another.
to_file
@@ -494,9 +497,9 @@
new_tree.lock_read()
try:
differ = DiffTree.from_trees_options(old_tree, new_tree, to_file,
- path_encoding,
- external_diff_options,
- old_label, new_label)
+ path_encoding,
+ external_diff_options,
+ old_label, new_label, using)
return differ.show_diff(specific_files, extra_trees)
finally:
new_tree.unlock()
@@ -565,6 +568,9 @@
self.to_file = to_file
self.path_encoding = path_encoding
+ def finish(self):
+ pass
+
@classmethod
def from_diff_tree(klass, diff_tree):
return klass(diff_tree.old_tree, diff_tree.new_tree,
@@ -590,6 +596,9 @@
def __init__(self, differs):
self.differs = differs
+ def finish(self):
+ pass
+
@classmethod
def from_diff_tree(klass, diff_tree):
return klass(diff_tree.differs)
@@ -736,6 +745,76 @@
return self.CHANGED
+class DiffFromTool(DiffPath):
+
+ def __init__(self, command_template, old_tree, new_tree, to_file,
+ path_encoding='utf-8'):
+ DiffPath.__init__(self, old_tree, new_tree, to_file, path_encoding)
+ self.command_template = command_template
+ self._root = tempfile.mkdtemp(prefix='bzr-diff-')
+
+ @classmethod
+ def from_string(klass, command_string, old_tree, new_tree, to_file,
+ path_encoding='utf-8'):
+ command_template = commands.shlex_split_unicode(command_string)
+ command_template.extend(['%(old_path)s', '%(new_path)s'])
+ return klass(command_template, old_tree, new_tree, to_file,
+ path_encoding)
+
+ @classmethod
+ def make_from_diff_tree(klass, command_string):
+ def from_diff_tree(diff_tree):
+ return klass.from_string(command_string, diff_tree.old_tree,
+ diff_tree.new_tree, diff_tree.to_file)
+ return from_diff_tree
+
+ def _get_command(self, old_path, new_path):
+ my_map = {'old_path': old_path, 'new_path': new_path}
+ return [t % my_map for t in self.command_template]
+
+ def _execute(self, old_path, new_path):
+ proc = subprocess.Popen(self._get_command(old_path, new_path),
+ stdout=subprocess.PIPE, cwd=self._root)
+ self.to_file.write(proc.stdout.read())
+ return proc.wait()
+
+ def _write_file(self, file_id, tree, prefix, old_path):
+ full_old_path = osutils.pathjoin(self._root, prefix, old_path)
+ parent_dir = osutils.dirname(full_old_path)
+ try:
+ os.makedirs(parent_dir)
+ except OSError, e:
+ if e.errno != errno.EEXIST:
+ raise
+ source = tree.get_file(file_id)
+ try:
+ target = open(full_old_path, 'wb')
+ try:
+ osutils.pumpfile(source, target)
+ finally:
+ target.close()
+ finally:
+ source.close()
+ return full_old_path
+
+ def _prepare_files(self, file_id, old_path, new_path):
+ old_disk_path = self._write_file(file_id, self.old_tree, 'old',
+ old_path)
+ new_disk_path = self._write_file(file_id, self.new_tree, 'new',
+ new_path)
+ return old_disk_path, new_disk_path
+
+ def finish(self):
+ shutil.rmtree(self._root)
+
+ def diff(self, file_id, old_path, new_path, old_kind, new_kind):
+ if (old_kind, new_kind) != ('file', 'file'):
+ return DiffPath.CANNOT_DIFF
+ self._prepare_files(file_id, old_path, new_path)
+ self._execute(osutils.pathjoin('old', old_path),
+ osutils.pathjoin('new', new_path))
+
+
class DiffTree(object):
"""Provides textual representations of the difference between two trees.
@@ -781,7 +860,7 @@
@classmethod
def from_trees_options(klass, old_tree, new_tree, to_file,
path_encoding, external_diff_options, old_label,
- new_label):
+ new_label, using):
"""Factory for producing a DiffTree.
Designed to accept options used by show_diff_trees.
@@ -793,7 +872,12 @@
binary to perform file comparison, using supplied options.
:param old_label: Prefix to use for old file labels
:param new_label: Prefix to use for new file labels
+ :param using: Commandline to use to invoke an external diff tool
"""
+ if using is not None:
+ extra_factories = [DiffFromTool.make_from_diff_tree(using)]
+ else:
+ extra_factories = []
if external_diff_options:
assert isinstance(external_diff_options, basestring)
opts = external_diff_options.split()
@@ -803,7 +887,8 @@
diff_file = internal_diff
diff_text = DiffText(old_tree, new_tree, to_file, path_encoding,
old_label, new_label, diff_file)
- return klass(old_tree, new_tree, to_file, path_encoding, diff_text)
+ return klass(old_tree, new_tree, to_file, path_encoding, diff_text,
+ extra_factories)
def show_diff(self, specific_files, extra_trees=None):
"""Write tree diff to self.to_file
@@ -811,6 +896,13 @@
:param sepecific_files: the specific files to compare (recursive)
:param extra_trees: extra trees to use for mapping paths to file_ids
"""
+ try:
+ return self._show_diff(specific_files, extra_trees)
+ finally:
+ for differ in self.differs:
+ differ.finish()
+
+ def _show_diff(self, specific_files, extra_trees):
# TODO: Generation of pseudo-diffs for added/deleted files could
# be usefully made into a much faster special case.
iterator = self.new_tree._iter_changes(self.old_tree,
=== modified file 'bzrlib/tests/test_diff.py'
--- a/bzrlib/tests/test_diff.py 2007-12-19 23:40:39 +0000
+++ b/bzrlib/tests/test_diff.py 2007-12-26 21:13:53 +0000
@@ -21,13 +21,14 @@
from tempfile import TemporaryFile
from bzrlib.diff import (
- internal_diff,
- external_diff,
+ DiffFromTool,
DiffPath,
- show_diff_trees,
DiffSymlink,
DiffTree,
DiffText,
+ external_diff,
+ internal_diff,
+ show_diff_trees,
)
from bzrlib.errors import BinaryFile, NoDiff
import bzrlib.osutils as osutils
@@ -1233,3 +1234,50 @@
from bzrlib._patiencediff_py import recurse_matches_py
self.assertIs(recurse_matches_py,
bzrlib.patiencediff.recurse_matches)
+
+
+class TestDiffFromTool(TestCaseWithTransport):
+
+ def test_from_string(self):
+ diff_obj = DiffFromTool.from_string('diff', None, None, None)
+ self.addCleanup(diff_obj.finish)
+ self.assertEqual(['diff', '%(old_path)s', '%(new_path)s'],
+ diff_obj.command_template)
+ diff_obj = DiffFromTool.from_string('diff -u\\ 5', None, None, None)
+ self.assertEqual(['diff', '-u 5', '%(old_path)s', '%(new_path)s'],
+ diff_obj.command_template)
+ self.assertEqual(['diff', '-u 5', 'old-path', 'new-path'],
+ diff_obj._get_command('old-path', 'new-path'))
+
+ def test_execute(self):
+ output = StringIO()
+ diff_obj = DiffFromTool(['python', '-c',
+ 'print "%(old_path)s %(new_path)s"'],
+ None, None, output)
+ self.addCleanup(diff_obj.finish)
+ diff_obj._execute('old', 'new')
+ self.assertEqual(output.getvalue(), 'old new\n')
+
+ def test_prepare_files(self):
+ output = StringIO()
+ tree = self.make_branch_and_tree('tree')
+ self.build_tree_contents([('tree/file', 'oldcontent')])
+ tree.add('file', 'file-id')
+ tree.commit('old tree')
+ self.build_tree_contents([('tree/file', 'newcontent')])
+ old_tree = tree.basis_tree()
+ old_tree.lock_read()
+ self.addCleanup(old_tree.unlock)
+ diff_obj = DiffFromTool(['python', '-c',
+ 'print "%(old_path)s %(new_path)s"'],
+ old_tree, tree, output)
+ self.addCleanup(diff_obj.finish)
+ self.assertContainsRe(diff_obj._root, 'bzr-diff-[^/]*')
+ old_path, new_path = diff_obj._prepare_files('file-id', 'oldname',
+ 'newname')
+ self.assertContainsRe(old_path, 'old/oldname$')
+ self.assertContainsRe(new_path, 'new/newname$')
+ self.assertFileEqual('oldcontent', old_path)
+ self.assertFileEqual('newcontent', new_path)
+ # make sure we can create files with the same parent directories
+ diff_obj._prepare_files('file-id', 'oldname2', 'newname2')
More information about the bazaar-commits
mailing list