46
49
from bzrlib.trace import mutter, note, warning
52
class AtTemplate(string.Template):
53
"""Templating class that uses @ instead of $."""
49
58
# TODO: Rather than building a changeset object, we should probably
50
59
# invoke callbacks on an object. That object can either accumulate a
51
60
# list, write them out directly, etc etc.
172
181
if not diff_opts:
183
if sys.platform == 'win32':
184
# Popen doesn't do the proper encoding for external commands
185
# Since we are dealing with an ANSI api, use mbcs encoding
186
old_filename = old_filename.encode('mbcs')
187
new_filename = new_filename.encode('mbcs')
174
188
diffcmd = ['diff',
175
189
'--label', old_filename,
275
def _get_trees_to_diff(path_list, revision_specs, old_url, new_url,
289
def get_trees_and_branches_to_diff(path_list, revision_specs, old_url, new_url,
277
291
"""Get the trees and specific files to diff given a list of paths.
279
293
This method works out the trees to be diff'ed and the files of
294
308
if True and a view is set, apply the view or check that the paths
297
a tuple of (old_tree, new_tree, specific_files, extra_trees) where
298
extra_trees is a sequence of additional trees to search in for
311
a tuple of (old_tree, new_tree, old_branch, new_branch,
312
specific_files, extra_trees) where extra_trees is a sequence of
313
additional trees to search in for file-ids.
301
315
# Get the old and new revision specs
302
316
old_revision_spec = None
336
350
views.check_path_in_view(working_tree, relpath)
337
351
specific_files.append(relpath)
338
352
old_tree = _get_tree_to_diff(old_revision_spec, working_tree, branch)
340
355
# Get the new location
341
356
if new_url is None:
349
364
specific_files.append(relpath)
350
365
new_tree = _get_tree_to_diff(new_revision_spec, working_tree, branch,
351
366
basis_is_default=working_tree is None)
353
369
# Get the specific files (all files is None, no files is [])
354
370
if make_paths_wt_relative and working_tree is not None:
373
389
extra_trees = None
374
390
if working_tree is not None and working_tree not in (old_tree, new_tree):
375
391
extra_trees = (working_tree,)
376
return old_tree, new_tree, specific_files, extra_trees
392
return old_tree, new_tree, old_branch, new_branch, specific_files, extra_trees
378
395
def _get_tree_to_diff(spec, tree=None, branch=None, basis_is_default=True):
379
396
if branch is None and tree is not None:
664
681
def from_string(klass, command_string, old_tree, new_tree, to_file,
665
682
path_encoding='utf-8'):
666
683
command_template = commands.shlex_split_unicode(command_string)
667
command_template.extend(['%(old_path)s', '%(new_path)s'])
684
if '@' not in command_string:
685
command_template.extend(['@old_path', '@new_path'])
668
686
return klass(command_template, old_tree, new_tree, to_file,
678
696
def _get_command(self, old_path, new_path):
679
697
my_map = {'old_path': old_path, 'new_path': new_path}
680
return [t % my_map for t in self.command_template]
698
return [AtTemplate(t).substitute(my_map) for t in
699
self.command_template]
682
701
def _execute(self, old_path, new_path):
683
702
command = self._get_command(old_path, new_path)
706
def _write_file(self, file_id, tree, prefix, relpath):
725
def _write_file(self, file_id, tree, prefix, relpath, force_temp=False,
727
if not force_temp and isinstance(tree, WorkingTree):
728
return tree.abspath(tree.id2path(file_id))
707
730
full_path = osutils.pathjoin(self._root, prefix, relpath)
708
if self._try_symlink_root(tree, prefix):
731
if not force_temp and self._try_symlink_root(tree, prefix):
710
733
parent_dir = osutils.dirname(full_path)
725
osutils.make_readonly(full_path)
749
osutils.make_readonly(full_path)
726
750
mtime = tree.get_file_mtime(file_id)
727
751
os.utime(full_path, (mtime, mtime))
730
def _prepare_files(self, file_id, old_path, new_path):
754
def _prepare_files(self, file_id, old_path, new_path, force_temp=False,
755
allow_write_new=False):
731
756
old_disk_path = self._write_file(file_id, self.old_tree, 'old',
757
old_path, force_temp)
733
758
new_disk_path = self._write_file(file_id, self.new_tree, 'new',
759
new_path, force_temp,
760
allow_write=allow_write_new)
735
761
return old_disk_path, new_disk_path
737
763
def finish(self):
745
771
def diff(self, file_id, old_path, new_path, old_kind, new_kind):
746
772
if (old_kind, new_kind) != ('file', 'file'):
747
773
return DiffPath.CANNOT_DIFF
748
self._prepare_files(file_id, old_path, new_path)
749
self._execute(osutils.pathjoin('old', old_path),
750
osutils.pathjoin('new', new_path))
774
(old_disk_path, new_disk_path) = self._prepare_files(
775
file_id, old_path, new_path)
776
self._execute(old_disk_path, new_disk_path)
778
def edit_file(self, file_id):
779
"""Use this tool to edit a file.
781
A temporary copy will be edited, and the new contents will be
784
:param file_id: The id of the file to edit.
785
:return: The new contents of the file.
787
old_path = self.old_tree.id2path(file_id)
788
new_path = self.new_tree.id2path(file_id)
789
new_abs_path = self._prepare_files(file_id, old_path, new_path,
790
allow_write_new=True,
792
command = self._get_command(osutils.pathjoin('old', old_path),
793
osutils.pathjoin('new', new_path))
794
subprocess.call(command, cwd=self._root)
795
new_file = open(new_abs_path, 'r')
797
return new_file.read()
753
802
class DiffTree(object):