18
18
from bzrlib import (
19
19
branch as _mod_branch,
23
revision as _mod_revision
27
class SvnDiffWriter(object):
29
def __init__(self, repository, base_revision_id):
30
self.repository = repository
31
self.base_revision_id = base_revision_id
32
self.tree_rev_info = {}
34
def get_svn_rev_info(self, tree):
35
if tree in self.tree_rev_info:
36
return self.tree_rev_info[tree]
37
revision_id = tree.get_revision_id()
38
if revision_id == self.base_revision_id:
39
rev_info = '(working copy)'
40
elif _mod_revision.is_null(revision_id):
41
rev_info = '(revision 0)'
43
info = self.repository.lookup_revision_id(revision_id)
44
rev_info = '(revision %d)' % info[0][2]
45
self.tree_rev_info[tree] = rev_info
48
def diff_text(self, difftext, file_id, old_path, new_path, old_kind, new_kind):
49
if 'file' not in (old_kind, new_kind):
50
return difftext.CANNOT_DIFF
51
from_file_id = to_file_id = file_id
52
if old_kind == 'file':
53
old_date = self.get_svn_rev_info(difftext.old_tree)
54
elif old_kind is None:
58
return difftext.CANNOT_DIFF
59
if new_kind == 'file':
60
new_date = self.get_svn_rev_info(difftext.new_tree)
61
elif new_kind is None:
65
return difftext.CANNOT_DIFF
66
from_label = '%s%s\t%s' % (difftext.old_label, old_path, old_date or '(revision 0)')
67
to_label = '%s%s\t%s' % (difftext.new_label, new_path, new_date or '(revision 0)')
68
return difftext.diff_text(from_file_id, to_file_id, from_label, to_label)
26
from cStringIO import StringIO
28
from subvertpy import (
33
class SvnDiffTree(_mod_diff.DiffTree):
34
"""Provides a text representation between two trees, formatted for svn."""
36
def _get_svn_rev_info(self, tree, file_id):
38
rev = tree.inventory[file_id].revision
39
except errors.NoSuchId:
42
return '(working copy)'
44
info = self.repository.lookup_revision_id(rev)
45
except errors.NoSuchRevision:
46
return '(working copy)'
47
return '(revision %d)' % info[0][2]
49
def _write_contents_diff(self, path, old_version, old_contents, new_version, new_contents):
52
self.to_file.write("Index: %s\n" % path)
53
self.to_file.write("=" * 67 + "\n")
54
old_label = '%s\t%s' % (path, old_version)
55
new_label = '%s\t%s' % (path, new_version)
56
_mod_diff.internal_diff(old_label, old_contents,
57
new_label, new_contents,
60
def _write_properties_diff(self, path, old_properties, new_properties):
61
if new_properties is None:
63
if old_properties is None:
66
for name in set(old_properties.keys() + new_properties.keys()):
67
oldval = old_properties.get(name)
68
newval = new_properties.get(name)
70
changed.append((name, oldval, newval))
73
self.to_file.write("Property changes on: %s\n" % path)
74
self.to_file.write("_" * 67 + "\n")
75
for (name, old_value, new_value) in changed:
77
self.to_file.write("Added: %s\n\t+%s\n" % (name, new_value))
78
elif new_value is None:
79
self.to_file.write("Removed: %s\n\t-%s\n" % (name, old_value))
81
self.to_file.write("Changed: %s\n\t-%s\n\t+%s\n" % (name, old_value, new_value))
83
def _get_file_properties(self, tree, path, kind, executable):
84
if kind in (None, "directory"):
88
ret[properties.PROP_EXECUTABLE] = properties.PROP_EXECUTABLE_VALUE
90
ret[properties.PROP_SPECIAL] = properties.PROP_SPECIAL_VALUE
93
def _get_file_contents(self, tree, file_id, path, kind):
94
if kind in (None, "directory"):
97
return ["link %s" % tree.get_symlink_target(file_id)]
98
return tree.get_file(file_id).readlines()
100
def _show_diff(self, specific_files, extra_trees):
101
iterator = self.new_tree.iter_changes(self.old_tree,
102
specific_files=specific_files,
103
extra_trees=extra_trees,
104
require_versioned=True)
106
def get_encoded_path(path):
108
return path.encode(self.path_encoding, "replace")
109
for (file_id, paths, changed_content, versioned, parent, name, kind,
110
executable) in iterator:
111
# The root does not get diffed, and items with no known kind (that
112
# is, missing) in both trees are skipped as well.
113
if parent == (None, None) or kind == (None, None):
115
oldpath, newpath = paths
116
oldpath_encoded = get_encoded_path(paths[0])
117
newpath_encoded = get_encoded_path(paths[1])
118
old_present = (kind[0] is not None and versioned[0])
119
new_present = (kind[1] is not None and versioned[1])
120
renamed = (parent[0], name[0]) != (parent[1], name[1])
121
old_properties = self._get_file_properties(self.old_tree, oldpath_encoded, kind[0], executable[0])
122
new_properties = self._get_file_properties(self.new_tree, newpath_encoded, kind[1], executable[1])
123
old_version = self._get_svn_rev_info(self.old_tree, file_id)
124
new_version = self._get_svn_rev_info(self.new_tree, file_id)
126
if oldpath_encoded == newpath_encoded:
128
old_contents = self._get_file_contents(self.old_tree, file_id, oldpath_encoded, kind[0])
129
new_contents = self._get_file_contents(self.new_tree, file_id, newpath_encoded, kind[1])
130
self._write_contents_diff(oldpath_encoded, old_version, old_contents, new_version, new_contents)
131
self._write_properties_diff(oldpath_encoded, old_properties, new_properties)
133
old_contents = self._get_file_contents(self.old_tree, file_id, oldpath_encoded, kind[0])
134
new_contents = self._get_file_contents(self.new_tree, file_id, newpath_encoded, kind[1])
135
self._write_contents_diff(oldpath_encoded, old_version, old_contents, new_version, [])
136
self._write_contents_diff(newpath_encoded, old_version, [], new_version, new_contents)
137
self._write_properties_diff(newpath_encoded, {}, new_properties)
139
has_changes = (changed_content or renamed)
71
144
class SvnMergeDirective(merge_directive._BaseMergeDirective):
77
150
def _generate_diff(cls, repository, svn_repository, revision_id, ancestor_id):
78
from bzrlib.diff import DiffText
79
writer = SvnDiffWriter(svn_repository, revision_id)
80
def DiffText_diff(self, file_id, old_path, new_path, old_kind, new_kind):
81
return writer.diff_text(self, file_id, old_path, new_path, old_kind, new_kind)
82
old_DiffText_diff = DiffText.diff
83
DiffText.diff = DiffText_diff
84
patch = merge_directive._BaseMergeDirective._generate_diff(
85
repository, revision_id, ancestor_id)
86
DiffText.diff = old_DiffText_diff
151
tree_1 = repository.revision_tree(ancestor_id)
152
tree_2 = repository.revision_tree(revision_id)
154
differ = SvnDiffTree.from_trees_options(tree_1, tree_2, s, 'utf8', None,
156
differ.repository = svn_repository
157
differ.show_diff(None, None)
90
161
def from_objects(cls, repository, revision_id, time, timezone,