~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/changeset.py

Merge from integration

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
#    You should have received a copy of the GNU General Public License
14
14
#    along with this program; if not, write to the Free Software
15
15
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
"""Represent and apply a changeset.
 
18
 
 
19
Conflicts in applying a changeset are represented as exceptions.
 
20
 
 
21
This only handles the in-memory objects representing changesets, which are
 
22
primarily used by the merge code. 
 
23
"""
 
24
 
16
25
import os.path
17
26
import errno
18
 
import patch
19
27
import stat
20
28
from tempfile import mkdtemp
21
29
from shutil import rmtree
22
 
from bzrlib.trace import mutter
 
30
from itertools import izip
 
31
 
 
32
from bzrlib.trace import mutter, warning
23
33
from bzrlib.osutils import rename, sha_file
24
34
import bzrlib
25
 
from itertools import izip
26
 
 
27
 
# XXX: mbp: I'm not totally convinced that we should handle conflicts
28
 
# as part of changeset application, rather than only in the merge
29
 
# operation.
30
 
 
31
 
"""Represent and apply a changeset
32
 
 
33
 
Conflicts in applying a changeset are represented as exceptions.
34
 
"""
 
35
from bzrlib.errors import BzrCheckError
35
36
 
36
37
__docformat__ = "restructuredtext"
37
38
 
441
442
        return out_path
442
443
 
443
444
    def apply(self, filename, conflict_handler, reverse=False):
 
445
        import bzrlib.patch
444
446
        temp_dir = mkdtemp(prefix="bzr-")
445
447
        try:
446
448
            new_file = filename+".new"
452
454
            else:
453
455
                base = other_file
454
456
                other = base_file
455
 
            status = patch.diff3(new_file, filename, base, other)
 
457
            status = bzrlib.patch.diff3(new_file, filename, base, other)
456
458
            if status == 0:
457
459
                os.chmod(new_file, os.stat(filename).st_mode)
458
460
                rename(new_file, filename)
631
633
        if self.id  == self.parent:
632
634
            raise ParentIDIsSelf(self)
633
635
 
634
 
    def __str__(self):
 
636
    def __repr__(self):
635
637
        return "ChangesetEntry(%s)" % self.id
636
638
 
 
639
    __str__ = __repr__
 
640
 
637
641
    def __get_dir(self):
638
642
        if self.path is None:
639
643
            return None
748
752
        """
749
753
        orig_path = self.get_cset_path(False)
750
754
        mod_path = self.get_cset_path(True)
751
 
        if orig_path is not None:
 
755
        if orig_path and orig_path.startswith('./'):
752
756
            orig_path = orig_path[2:]
753
 
        if mod_path is not None:
 
757
        if mod_path and mod_path.startswith('./'):
754
758
            mod_path = mod_path[2:]
755
759
        if orig_path == mod_path:
756
760
            return orig_path
772
776
        :type reverse: bool
773
777
        :rtype: str
774
778
        """
775
 
        mutter("Finding new path for %s" % self.summarize_name())
 
779
        mutter("Finding new path for %s", self.summarize_name())
776
780
        if reverse:
777
781
            parent = self.parent
778
782
            to_dir = self.dir
794
798
                raise SourceRootHasName(self, to_name)
795
799
            else:
796
800
                return '.'
797
 
        if from_dir == to_dir:
 
801
        parent_entry = changeset.entries.get(parent)
 
802
        if parent_entry is None:
798
803
            dir = os.path.dirname(id_map[self.id])
799
804
        else:
800
 
            mutter("path, new_path: %r %r" % (self.path, self.new_path))
801
 
            parent_entry = changeset.entries[parent]
 
805
            mutter("path, new_path: %r %r", self.path, self.new_path)
802
806
            dir = parent_entry.get_new_path(id_map, changeset, reverse)
803
807
        if from_name == to_name:
804
808
            name = os.path.basename(id_map[self.id])
935
939
            temp_name[entry.id] = None
936
940
 
937
941
        elif entry.needs_rename():
 
942
            if entry.is_creation(reverse):
 
943
                continue
938
944
            to_name = os.path.join(temp_dir, str(i))
939
945
            src_path = inventory.get(entry.id)
940
946
            if src_path is not None:
981
987
            entry.apply(new_path, conflict_handler, reverse)
982
988
            changed_inventory[entry.id] = new_tree_path
983
989
        elif entry.needs_rename():
 
990
            if entry.is_deletion(reverse):
 
991
                continue
984
992
            if old_path is None:
985
993
                continue
986
994
            try:
 
995
                mutter('rename %s to final name %s', old_path, new_path)
987
996
                rename(old_path, new_path)
988
997
                changed_inventory[entry.id] = new_tree_path
989
998
            except OSError, e:
990
 
                raise Exception ("%s is missing" % new_path)
 
999
                raise BzrCheckError('failed to rename %s to %s for changeset entry %s: %s'
 
1000
                        % (old_path, new_path, entry, e))
991
1001
 
992
1002
class TargetExists(Exception):
993
1003
    def __init__(self, entry, target):
1208
1218
    #apply changes that don't affect filenames
1209
1219
    for entry in changeset.entries.itervalues():
1210
1220
        if not entry.is_creation_or_deletion() and not entry.is_boring():
 
1221
            if entry.id not in inventory:
 
1222
                warning("entry {%s} no longer present, can't be updated",
 
1223
                        entry.id)
 
1224
                continue
1211
1225
            path = os.path.join(dir, inventory[entry.id])
1212
1226
            entry.apply(path, conflict_handler, reverse)
1213
1227