~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/diff.py

  • Committer: Martin Pool
  • Date: 2009-11-16 02:26:32 UTC
  • mto: This revision was merged to the branch mainline in revision 4880.
  • Revision ID: mbp@sourcefrog.net-20091116022632-261trs2osy8oupe3
Convert version-info to use TextUIOutputStream

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
import os
19
19
import re
20
20
import shutil
21
 
import string
22
21
import sys
23
22
 
24
23
from bzrlib.lazy_import import lazy_import
39
38
    timestamp,
40
39
    views,
41
40
    )
42
 
 
43
 
from bzrlib.workingtree import WorkingTree
44
41
""")
45
42
 
46
43
from bzrlib.symbol_versioning import (
49
46
from bzrlib.trace import mutter, note, warning
50
47
 
51
48
 
52
 
class AtTemplate(string.Template):
53
 
    """Templating class that uses @ instead of $."""
54
 
 
55
 
    delimiter = '@'
56
 
 
57
 
 
58
49
# TODO: Rather than building a changeset object, we should probably
59
50
# invoke callbacks on an object.  That object can either accumulate a
60
51
# list, write them out directly, etc etc.
453
444
 
454
445
def _patch_header_date(tree, file_id, path):
455
446
    """Returns a timestamp suitable for use in a patch header."""
456
 
    try:
457
 
        mtime = tree.get_file_mtime(file_id, path)
458
 
    except errors.FileTimestampUnavailable:
459
 
        mtime = 0
 
447
    mtime = tree.get_file_mtime(file_id, path)
460
448
    return timestamp.format_patch_date(mtime)
461
449
 
462
450
 
684
672
    def from_string(klass, command_string, old_tree, new_tree, to_file,
685
673
                    path_encoding='utf-8'):
686
674
        command_template = commands.shlex_split_unicode(command_string)
687
 
        if '@' not in command_string:
688
 
            command_template.extend(['@old_path', '@new_path'])
 
675
        command_template.extend(['%(old_path)s', '%(new_path)s'])
689
676
        return klass(command_template, old_tree, new_tree, to_file,
690
677
                     path_encoding)
691
678
 
698
685
 
699
686
    def _get_command(self, old_path, new_path):
700
687
        my_map = {'old_path': old_path, 'new_path': new_path}
701
 
        return [AtTemplate(t).substitute(my_map) for t in
702
 
                self.command_template]
 
688
        return [t % my_map for t in self.command_template]
703
689
 
704
690
    def _execute(self, old_path, new_path):
705
691
        command = self._get_command(old_path, new_path)
725
711
                raise
726
712
        return True
727
713
 
728
 
    def _write_file(self, file_id, tree, prefix, relpath, force_temp=False,
729
 
                    allow_write=False):
730
 
        if not force_temp and isinstance(tree, WorkingTree):
731
 
            return tree.abspath(tree.id2path(file_id))
732
 
        
 
714
    def _write_file(self, file_id, tree, prefix, relpath):
733
715
        full_path = osutils.pathjoin(self._root, prefix, relpath)
734
 
        if not force_temp and self._try_symlink_root(tree, prefix):
 
716
        if self._try_symlink_root(tree, prefix):
735
717
            return full_path
736
718
        parent_dir = osutils.dirname(full_path)
737
719
        try:
748
730
                target.close()
749
731
        finally:
750
732
            source.close()
751
 
        if not allow_write:
752
 
            osutils.make_readonly(full_path)
753
 
        try:
754
 
            mtime = tree.get_file_mtime(file_id)
755
 
        except errors.FileTimestampUnavailable:
756
 
            mtime = 0
 
733
        osutils.make_readonly(full_path)
 
734
        mtime = tree.get_file_mtime(file_id)
757
735
        os.utime(full_path, (mtime, mtime))
758
736
        return full_path
759
737
 
760
 
    def _prepare_files(self, file_id, old_path, new_path, force_temp=False,
761
 
                       allow_write_new=False):
 
738
    def _prepare_files(self, file_id, old_path, new_path):
762
739
        old_disk_path = self._write_file(file_id, self.old_tree, 'old',
763
 
                                         old_path, force_temp)
 
740
                                         old_path)
764
741
        new_disk_path = self._write_file(file_id, self.new_tree, 'new',
765
 
                                         new_path, force_temp,
766
 
                                         allow_write=allow_write_new)
 
742
                                         new_path)
767
743
        return old_disk_path, new_disk_path
768
744
 
769
745
    def finish(self):
777
753
    def diff(self, file_id, old_path, new_path, old_kind, new_kind):
778
754
        if (old_kind, new_kind) != ('file', 'file'):
779
755
            return DiffPath.CANNOT_DIFF
780
 
        (old_disk_path, new_disk_path) = self._prepare_files(
781
 
                                                file_id, old_path, new_path)
782
 
        self._execute(old_disk_path, new_disk_path)
783
 
 
784
 
    def edit_file(self, file_id):
785
 
        """Use this tool to edit a file.
786
 
 
787
 
        A temporary copy will be edited, and the new contents will be
788
 
        returned.
789
 
 
790
 
        :param file_id: The id of the file to edit.
791
 
        :return: The new contents of the file.
792
 
        """
793
 
        old_path = self.old_tree.id2path(file_id)
794
 
        new_path = self.new_tree.id2path(file_id)
795
 
        new_abs_path = self._prepare_files(file_id, old_path, new_path,
796
 
                                           allow_write_new=True,
797
 
                                           force_temp=True)[1]
798
 
        command = self._get_command(osutils.pathjoin('old', old_path),
799
 
                                    osutils.pathjoin('new', new_path))
800
 
        subprocess.call(command, cwd=self._root)
801
 
        new_file = open(new_abs_path, 'r')
802
 
        try:
803
 
            return new_file.read()
804
 
        finally:
805
 
            new_file.close()
 
756
        self._prepare_files(file_id, old_path, new_path)
 
757
        self._execute(osutils.pathjoin('old', old_path),
 
758
                      osutils.pathjoin('new', new_path))
806
759
 
807
760
 
808
761
class DiffTree(object):