/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/diff.py

  • Committer: Aaron Bentley
  • Date: 2008-02-24 16:42:13 UTC
  • mfrom: (3234 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3235.
  • Revision ID: aaron@aaronbentley.com-20080224164213-eza1lzru5bwuwmmj
Merge with bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
import difflib
18
18
import os
19
19
import re
 
20
import shutil
20
21
import sys
21
22
 
22
23
from bzrlib.lazy_import import lazy_import
28
29
 
29
30
from bzrlib import (
30
31
    bzrdir,
 
32
    commands,
31
33
    errors,
32
34
    osutils,
33
35
    patiencediff,
386
388
 
387
389
    other_paths = []
388
390
    make_paths_wt_relative = True
 
391
    consider_relpath = True
389
392
    if path_list is None or len(path_list) == 0:
390
 
        # If no path is given, assume the current directory
 
393
        # If no path is given, the current working tree is used
391
394
        default_location = u'.'
 
395
        consider_relpath = False
392
396
    elif old_url is not None and new_url is not None:
393
397
        other_paths = path_list
394
398
        make_paths_wt_relative = False
402
406
        old_url = default_location
403
407
    working_tree, branch, relpath = \
404
408
        bzrdir.BzrDir.open_containing_tree_or_branch(old_url)
405
 
    if relpath != '':
 
409
    if consider_relpath and relpath != '':
406
410
        specific_files.append(relpath)
407
411
    old_tree = _get_tree_to_diff(old_revision_spec, working_tree, branch)
408
412
 
412
416
    if new_url != old_url:
413
417
        working_tree, branch, relpath = \
414
418
            bzrdir.BzrDir.open_containing_tree_or_branch(new_url)
415
 
        if relpath != '':
 
419
        if consider_relpath and relpath != '':
416
420
            specific_files.append(relpath)
417
421
    new_tree = _get_tree_to_diff(new_revision_spec, working_tree, branch,
418
422
        basis_is_default=working_tree is None)
467
471
                    external_diff_options=None,
468
472
                    old_label='a/', new_label='b/',
469
473
                    extra_trees=None,
470
 
                    path_encoding='utf8'):
 
474
                    path_encoding='utf8',
 
475
                    using=None):
471
476
    """Show in text form the changes from one tree to another.
472
477
 
473
478
    to_file
494
499
        new_tree.lock_read()
495
500
        try:
496
501
            differ = DiffTree.from_trees_options(old_tree, new_tree, to_file,
497
 
                                                   path_encoding,
498
 
                                                   external_diff_options,
499
 
                                                   old_label, new_label)
 
502
                                                 path_encoding,
 
503
                                                 external_diff_options,
 
504
                                                 old_label, new_label, using)
500
505
            return differ.show_diff(specific_files, extra_trees)
501
506
        finally:
502
507
            new_tree.unlock()
565
570
        self.to_file = to_file
566
571
        self.path_encoding = path_encoding
567
572
 
 
573
    def finish(self):
 
574
        pass
 
575
 
568
576
    @classmethod
569
577
    def from_diff_tree(klass, diff_tree):
570
578
        return klass(diff_tree.old_tree, diff_tree.new_tree,
590
598
    def __init__(self, differs):
591
599
        self.differs = differs
592
600
 
 
601
    def finish(self):
 
602
        pass
 
603
 
593
604
    @classmethod
594
605
    def from_diff_tree(klass, diff_tree):
595
606
        return klass(diff_tree.differs)
736
747
        return self.CHANGED
737
748
 
738
749
 
 
750
class DiffFromTool(DiffPath):
 
751
 
 
752
    def __init__(self, command_template, old_tree, new_tree, to_file,
 
753
                 path_encoding='utf-8'):
 
754
        DiffPath.__init__(self, old_tree, new_tree, to_file, path_encoding)
 
755
        self.command_template = command_template
 
756
        self._root = tempfile.mkdtemp(prefix='bzr-diff-')
 
757
 
 
758
    @classmethod
 
759
    def from_string(klass, command_string, old_tree, new_tree, to_file,
 
760
                    path_encoding='utf-8'):
 
761
        command_template = commands.shlex_split_unicode(command_string)
 
762
        command_template.extend(['%(old_path)s', '%(new_path)s'])
 
763
        return klass(command_template, old_tree, new_tree, to_file,
 
764
                     path_encoding)
 
765
 
 
766
    @classmethod
 
767
    def make_from_diff_tree(klass, command_string):
 
768
        def from_diff_tree(diff_tree):
 
769
            return klass.from_string(command_string, diff_tree.old_tree,
 
770
                                     diff_tree.new_tree, diff_tree.to_file)
 
771
        return from_diff_tree
 
772
 
 
773
    def _get_command(self, old_path, new_path):
 
774
        my_map = {'old_path': old_path, 'new_path': new_path}
 
775
        return [t % my_map for t in self.command_template]
 
776
 
 
777
    def _execute(self, old_path, new_path):
 
778
        command = self._get_command(old_path, new_path)
 
779
        try:
 
780
            proc = subprocess.Popen(command, stdout=subprocess.PIPE,
 
781
                                    cwd=self._root)
 
782
        except OSError, e:
 
783
            if e.errno == errno.ENOENT:
 
784
                raise errors.ExecutableMissing(command[0])
 
785
            else:
 
786
                raise
 
787
        self.to_file.write(proc.stdout.read())
 
788
        return proc.wait()
 
789
 
 
790
    def _try_symlink_root(self, tree, prefix):
 
791
        if not (getattr(tree, 'abspath', None) is not None
 
792
                and osutils.has_symlinks()):
 
793
            return False
 
794
        try:
 
795
            os.symlink(tree.abspath(''), osutils.pathjoin(self._root, prefix))
 
796
        except OSError, e:
 
797
            if e.errno != errno.EEXIST:
 
798
                raise
 
799
        return True
 
800
 
 
801
    def _write_file(self, file_id, tree, prefix, relpath):
 
802
        full_path = osutils.pathjoin(self._root, prefix, relpath)
 
803
        if self._try_symlink_root(tree, prefix):
 
804
            return full_path
 
805
        parent_dir = osutils.dirname(full_path)
 
806
        try:
 
807
            os.makedirs(parent_dir)
 
808
        except OSError, e:
 
809
            if e.errno != errno.EEXIST:
 
810
                raise
 
811
        source = tree.get_file(file_id, relpath)
 
812
        try:
 
813
            target = open(full_path, 'wb')
 
814
            try:
 
815
                osutils.pumpfile(source, target)
 
816
            finally:
 
817
                target.close()
 
818
        finally:
 
819
            source.close()
 
820
        osutils.make_readonly(full_path)
 
821
        mtime = tree.get_file_mtime(file_id)
 
822
        os.utime(full_path, (mtime, mtime))
 
823
        return full_path
 
824
 
 
825
    def _prepare_files(self, file_id, old_path, new_path):
 
826
        old_disk_path = self._write_file(file_id, self.old_tree, 'old',
 
827
                                         old_path)
 
828
        new_disk_path = self._write_file(file_id, self.new_tree, 'new',
 
829
                                         new_path)
 
830
        return old_disk_path, new_disk_path
 
831
 
 
832
    def finish(self):
 
833
        osutils.rmtree(self._root)
 
834
 
 
835
    def diff(self, file_id, old_path, new_path, old_kind, new_kind):
 
836
        if (old_kind, new_kind) != ('file', 'file'):
 
837
            return DiffPath.CANNOT_DIFF
 
838
        self._prepare_files(file_id, old_path, new_path)
 
839
        self._execute(osutils.pathjoin('old', old_path),
 
840
                      osutils.pathjoin('new', new_path))
 
841
 
 
842
 
739
843
class DiffTree(object):
740
844
    """Provides textual representations of the difference between two trees.
741
845
 
781
885
    @classmethod
782
886
    def from_trees_options(klass, old_tree, new_tree, to_file,
783
887
                           path_encoding, external_diff_options, old_label,
784
 
                           new_label):
 
888
                           new_label, using):
785
889
        """Factory for producing a DiffTree.
786
890
 
787
891
        Designed to accept options used by show_diff_trees.
793
897
            binary to perform file comparison, using supplied options.
794
898
        :param old_label: Prefix to use for old file labels
795
899
        :param new_label: Prefix to use for new file labels
 
900
        :param using: Commandline to use to invoke an external diff tool
796
901
        """
 
902
        if using is not None:
 
903
            extra_factories = [DiffFromTool.make_from_diff_tree(using)]
 
904
        else:
 
905
            extra_factories = []
797
906
        if external_diff_options:
798
907
            assert isinstance(external_diff_options, basestring)
799
908
            opts = external_diff_options.split()
803
912
            diff_file = internal_diff
804
913
        diff_text = DiffText(old_tree, new_tree, to_file, path_encoding,
805
914
                             old_label, new_label, diff_file)
806
 
        return klass(old_tree, new_tree, to_file, path_encoding, diff_text)
 
915
        return klass(old_tree, new_tree, to_file, path_encoding, diff_text,
 
916
                     extra_factories)
807
917
 
808
918
    def show_diff(self, specific_files, extra_trees=None):
809
919
        """Write tree diff to self.to_file
811
921
        :param sepecific_files: the specific files to compare (recursive)
812
922
        :param extra_trees: extra trees to use for mapping paths to file_ids
813
923
        """
 
924
        try:
 
925
            return self._show_diff(specific_files, extra_trees)
 
926
        finally:
 
927
            for differ in self.differs:
 
928
                differ.finish()
 
929
 
 
930
    def _show_diff(self, specific_files, extra_trees):
814
931
        # TODO: Generation of pseudo-diffs for added/deleted files could
815
932
        # be usefully made into a much faster special case.
816
933
        iterator = self.new_tree._iter_changes(self.old_tree,