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
17
from bzrlib.trace import mutter
18
from bzrlib.errors import BzrError
17
19
from bzrlib.delta import compare_trees
18
from bzrlib.errors import BzrError
19
import bzrlib.errors as errors
20
from bzrlib.symbol_versioning import *
21
from bzrlib.textfile import check_text_lines
22
from bzrlib.trace import mutter
24
21
# TODO: Rather than building a changeset object, we should probably
25
22
# invoke callbacks on an object. That object can either accumulate a
26
23
# list, write them out directly, etc etc.
28
def internal_diff(old_filename, oldlines, new_filename, newlines, to_file,
25
def internal_diff(old_label, oldlines, new_label, newlines, to_file):
32
28
# FIXME: difflib is wrong if there is no trailing newline.
171
158
output = sys.stdout
173
160
if from_spec is None:
174
old_tree = b.bzrdir.open_workingtree()
176
old_tree = old_tree = old_tree.basis_tree()
161
old_tree = b.basis_tree()
178
old_tree = b.repository.revision_tree(from_spec.in_history(b).rev_id)
163
old_tree = b.revision_tree(from_spec.in_history(b).rev_id)
180
165
if revision2 is None:
182
new_tree = b.bzrdir.open_workingtree()
184
new_tree = b2.bzrdir.open_workingtree()
186
new_tree = b.repository.revision_tree(revision2.in_history(b).rev_id)
188
return show_diff_trees(old_tree, new_tree, output, specific_files,
189
external_diff_options)
192
def diff_cmd_helper(tree, specific_files, external_diff_options,
193
old_revision_spec=None, new_revision_spec=None,
194
old_label='a/', new_label='b/'):
195
"""Helper for cmd_diff.
201
The specific files to compare, or None
203
external_diff_options
204
If non-None, run an external diff, and pass it these options
207
If None, use basis tree as old revision, otherwise use the tree for
208
the specified revision.
211
If None, use working tree as new revision, otherwise use the tree for
212
the specified revision.
214
The more general form is show_diff_trees(), where the caller
215
supplies any two trees.
220
revision_id = spec.in_store(tree.branch).rev_id
221
return tree.branch.repository.revision_tree(revision_id)
222
if old_revision_spec is None:
223
old_tree = tree.basis_tree()
225
old_tree = spec_tree(old_revision_spec)
227
if new_revision_spec is None:
230
new_tree = spec_tree(new_revision_spec)
232
return show_diff_trees(old_tree, new_tree, sys.stdout, specific_files,
233
external_diff_options,
234
old_label=old_label, new_label=new_label)
166
new_tree = b.working_tree()
168
new_tree = b.revision_tree(revision2.in_history(b).rev_id)
170
show_diff_trees(old_tree, new_tree, output, specific_files,
171
external_diff_options)
237
175
def show_diff_trees(old_tree, new_tree, to_file, specific_files=None,
238
external_diff_options=None,
239
old_label='a/', new_label='b/'):
176
external_diff_options=None):
240
177
"""Show in text form the changes from one tree to another.
245
182
external_diff_options
246
183
If set, use an external GNU diff and pass these options.
252
return _show_diff_trees(old_tree, new_tree, to_file,
253
specific_files, external_diff_options,
254
old_label=old_label, new_label=new_label)
261
def _show_diff_trees(old_tree, new_tree, to_file,
262
specific_files, external_diff_options,
263
old_label='a/', new_label='b/' ):
186
# TODO: Options to control putting on a prefix or suffix, perhaps as a format string
265
190
DEVNULL = '/dev/null'
266
191
# Windows users, don't panic about this filename -- it is a
281
204
diff_file = internal_diff
283
207
delta = compare_trees(old_tree, new_tree, want_unchanged=False,
284
208
specific_files=specific_files)
287
210
for path, file_id, kind in delta.removed:
289
print >>to_file, '=== removed %s %r' % (kind, old_label + path)
211
print >>to_file, '=== removed %s %r' % (kind, path)
290
212
old_tree.inventory[file_id].diff(diff_file, old_label + path, old_tree,
291
213
DEVNULL, None, None, to_file)
292
214
for path, file_id, kind in delta.added:
294
print >>to_file, '=== added %s %r' % (kind, new_label + path)
215
print >>to_file, '=== added %s %r' % (kind, path)
295
216
new_tree.inventory[file_id].diff(diff_file, new_label + path, new_tree,
296
217
DEVNULL, None, None, to_file,
298
219
for (old_path, new_path, file_id, kind,
299
220
text_modified, meta_modified) in delta.renamed:
301
221
prop_str = get_prop_change(meta_modified)
302
222
print >>to_file, '=== renamed %s %r => %r%s' % (
303
kind, old_label + old_path, new_label + new_path, prop_str)
223
kind, old_path, new_path, prop_str)
304
224
_maybe_diff_file_or_symlink(old_label, old_path, old_tree, file_id,
305
225
new_label, new_path, new_tree,
306
226
text_modified, kind, to_file, diff_file)
307
227
for path, file_id, kind, text_modified, meta_modified in delta.modified:
309
228
prop_str = get_prop_change(meta_modified)
310
print >>to_file, '=== modified %s %r%s' % (kind, old_label + path,
229
print >>to_file, '=== modified %s %r%s' % (kind, path, prop_str)
312
230
if text_modified:
313
231
_maybe_diff_file_or_symlink(old_label, path, old_tree, file_id,
314
232
new_label, path, new_tree,
315
233
True, kind, to_file, diff_file)
320
def _raise_if_doubly_unversioned(specific_files, old_tree, new_tree):
321
"""Complain if paths are not versioned in either tree."""
322
if not specific_files:
324
old_unversioned = old_tree.filter_unversioned_files(specific_files)
325
new_unversioned = new_tree.filter_unversioned_files(specific_files)
326
unversioned = old_unversioned.intersection(new_unversioned)
328
raise errors.PathsNotVersionedError(sorted(unversioned))
331
def _raise_if_nonexistent(paths, old_tree, new_tree):
332
"""Complain if paths are not in either inventory or tree.
334
It's OK with the files exist in either tree's inventory, or
335
if they exist in the tree but are not versioned.
337
This can be used by operations such as bzr status that can accept
338
unknown or ignored files.
340
mutter("check paths: %r", paths)
343
s = old_tree.filter_unversioned_files(paths)
344
s = new_tree.filter_unversioned_files(s)
345
s = [path for path in s if not new_tree.has_filename(path)]
347
raise errors.PathsDoNotExist(sorted(s))
350
236
def get_prop_change(meta_modified):
351
237
if meta_modified: