~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/diff.py

  • Committer: Martin Pool
  • Date: 2009-11-26 01:42:06 UTC
  • mfrom: (4827 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4828.
  • Revision ID: mbp@sourcefrog.net-20091126014206-qvf8jfpwpro558r4
merge news

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
21
22
import sys
22
23
 
23
24
from bzrlib.lazy_import import lazy_import
46
47
from bzrlib.trace import mutter, note, warning
47
48
 
48
49
 
 
50
class AtTemplate(string.Template):
 
51
    """Templating class that uses @ instead of $."""
 
52
 
 
53
    delimiter = '@'
 
54
 
 
55
 
49
56
# TODO: Rather than building a changeset object, we should probably
50
57
# invoke callbacks on an object.  That object can either accumulate a
51
58
# list, write them out directly, etc etc.
672
679
    def from_string(klass, command_string, old_tree, new_tree, to_file,
673
680
                    path_encoding='utf-8'):
674
681
        command_template = commands.shlex_split_unicode(command_string)
675
 
        command_template.extend(['%(old_path)s', '%(new_path)s'])
 
682
        if '@' not in command_string:
 
683
            command_template.extend(['@old_path', '@new_path'])
676
684
        return klass(command_template, old_tree, new_tree, to_file,
677
685
                     path_encoding)
678
686
 
685
693
 
686
694
    def _get_command(self, old_path, new_path):
687
695
        my_map = {'old_path': old_path, 'new_path': new_path}
688
 
        return [t % my_map for t in self.command_template]
 
696
        return [AtTemplate(t).substitute(my_map) for t in
 
697
                self.command_template]
689
698
 
690
699
    def _execute(self, old_path, new_path):
691
700
        command = self._get_command(old_path, new_path)
711
720
                raise
712
721
        return True
713
722
 
714
 
    def _write_file(self, file_id, tree, prefix, relpath):
 
723
    def _write_file(self, file_id, tree, prefix, relpath, force_temp=False,
 
724
                    allow_write=False):
715
725
        full_path = osutils.pathjoin(self._root, prefix, relpath)
716
 
        if self._try_symlink_root(tree, prefix):
 
726
        if not force_temp and self._try_symlink_root(tree, prefix):
717
727
            return full_path
718
728
        parent_dir = osutils.dirname(full_path)
719
729
        try:
730
740
                target.close()
731
741
        finally:
732
742
            source.close()
733
 
        osutils.make_readonly(full_path)
 
743
        if not allow_write:
 
744
            osutils.make_readonly(full_path)
734
745
        mtime = tree.get_file_mtime(file_id)
735
746
        os.utime(full_path, (mtime, mtime))
736
747
        return full_path
737
748
 
738
 
    def _prepare_files(self, file_id, old_path, new_path):
 
749
    def _prepare_files(self, file_id, old_path, new_path, force_temp=False,
 
750
                       allow_write_new=False):
739
751
        old_disk_path = self._write_file(file_id, self.old_tree, 'old',
740
 
                                         old_path)
 
752
                                         old_path, force_temp)
741
753
        new_disk_path = self._write_file(file_id, self.new_tree, 'new',
742
 
                                         new_path)
 
754
                                         new_path, force_temp,
 
755
                                         allow_write=allow_write_new)
743
756
        return old_disk_path, new_disk_path
744
757
 
745
758
    def finish(self):
757
770
        self._execute(osutils.pathjoin('old', old_path),
758
771
                      osutils.pathjoin('new', new_path))
759
772
 
 
773
    def edit_file(self, file_id):
 
774
        """Use this tool to edit a file.
 
775
 
 
776
        A temporary copy will be edited, and the new contents will be
 
777
        returned.
 
778
 
 
779
        :param file_id: The id of the file to edit.
 
780
        :return: The new contents of the file.
 
781
        """
 
782
        old_path = self.old_tree.id2path(file_id)
 
783
        new_path = self.new_tree.id2path(file_id)
 
784
        new_abs_path = self._prepare_files(file_id, old_path, new_path,
 
785
                                           allow_write_new=True,
 
786
                                           force_temp=True)[1]
 
787
        command = self._get_command(osutils.pathjoin('old', old_path),
 
788
                                    osutils.pathjoin('new', new_path))
 
789
        subprocess.call(command, cwd=self._root)
 
790
        new_file = open(new_abs_path, 'r')
 
791
        try:
 
792
            return new_file.read()
 
793
        finally:
 
794
            new_file.close()
 
795
 
760
796
 
761
797
class DiffTree(object):
762
798
    """Provides textual representations of the difference between two trees.