~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/diff.py

  • Committer: John Arbash Meinel
  • Date: 2008-08-20 16:14:09 UTC
  • mfrom: (3606.5.8 1.6)
  • mto: This revision was merged to the branch mainline in revision 3642.
  • Revision ID: john@arbash-meinel.com-20080820161409-pl5tzssd7wlxi7ma
Merge in 1.6rc5 and revert disabling default stack on policy

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
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
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
import difflib
18
18
import os
36
36
    patiencediff,
37
37
    textfile,
38
38
    timestamp,
39
 
    views,
40
39
    )
41
40
""")
42
41
 
43
42
from bzrlib.symbol_versioning import (
44
 
    deprecated_function,
45
 
    )
46
 
from bzrlib.trace import mutter, note, warning
 
43
        deprecated_function,
 
44
        one_three
 
45
        )
 
46
from bzrlib.trace import mutter, warning
47
47
 
48
48
 
49
49
# TODO: Rather than building a changeset object, we should probably
78
78
    # both sequences are empty.
79
79
    if not oldlines and not newlines:
80
80
        return
81
 
 
 
81
    
82
82
    if allow_binary is False:
83
83
        textfile.check_text_lines(oldlines)
84
84
        textfile.check_text_lines(newlines)
99
99
        ud[2] = ud[2].replace('-1,0', '-0,0')
100
100
    elif not newlines:
101
101
        ud[2] = ud[2].replace('+1,0', '+0,0')
 
102
    # work around for difflib emitting random spaces after the label
 
103
    ud[0] = ud[0][:-2] + '\n'
 
104
    ud[1] = ud[1][:-2] + '\n'
102
105
 
103
106
    for line in ud:
104
107
        to_file.write(line)
199
202
            break
200
203
        else:
201
204
            diffcmd.append('-u')
202
 
 
 
205
                  
203
206
        if diff_opts:
204
207
            diffcmd.extend(diff_opts)
205
208
 
206
209
        pipe = _spawn_external_diff(diffcmd, capture_errors=True)
207
210
        out,err = pipe.communicate()
208
211
        rc = pipe.returncode
209
 
 
 
212
        
210
213
        # internal_diff() adds a trailing newline, add one here for consistency
211
214
        out += '\n'
212
215
        if rc == 2:
247
250
                msg = 'signal %d' % (-rc)
248
251
            else:
249
252
                msg = 'exit code %d' % rc
250
 
 
251
 
            raise errors.BzrError('external diff failed with %s; command: %r'
 
253
                
 
254
            raise errors.BzrError('external diff failed with %s; command: %r' 
252
255
                                  % (rc, diffcmd))
253
256
 
254
257
 
272
275
                        new_abspath, e)
273
276
 
274
277
 
275
 
def _get_trees_to_diff(path_list, revision_specs, old_url, new_url,
276
 
    apply_view=True):
 
278
def _get_trees_to_diff(path_list, revision_specs, old_url, new_url):
277
279
    """Get the trees and specific files to diff given a list of paths.
278
280
 
279
281
    This method works out the trees to be diff'ed and the files of
290
292
    :param new_url:
291
293
        The url of the new branch or tree. If None, the tree to use is
292
294
        taken from the first path, if any, or the current working tree.
293
 
    :param apply_view:
294
 
        if True and a view is set, apply the view or check that the paths
295
 
        are within it
296
295
    :returns:
297
296
        a tuple of (old_tree, new_tree, specific_files, extra_trees) where
298
297
        extra_trees is a sequence of additional trees to search in for
332
331
    working_tree, branch, relpath = \
333
332
        bzrdir.BzrDir.open_containing_tree_or_branch(old_url)
334
333
    if consider_relpath and relpath != '':
335
 
        if working_tree is not None and apply_view:
336
 
            views.check_path_in_view(working_tree, relpath)
337
334
        specific_files.append(relpath)
338
335
    old_tree = _get_tree_to_diff(old_revision_spec, working_tree, branch)
339
336
 
344
341
        working_tree, branch, relpath = \
345
342
            bzrdir.BzrDir.open_containing_tree_or_branch(new_url)
346
343
        if consider_relpath and relpath != '':
347
 
            if working_tree is not None and apply_view:
348
 
                views.check_path_in_view(working_tree, relpath)
349
344
            specific_files.append(relpath)
350
345
    new_tree = _get_tree_to_diff(new_revision_spec, working_tree, branch,
351
346
        basis_is_default=working_tree is None)
352
347
 
353
348
    # Get the specific files (all files is None, no files is [])
354
349
    if make_paths_wt_relative and working_tree is not None:
355
 
        try:
356
 
            from bzrlib.builtins import safe_relpath_files
357
 
            other_paths = safe_relpath_files(working_tree, other_paths,
358
 
            apply_view=apply_view)
359
 
        except errors.FileInWrongBranch:
360
 
            raise errors.BzrCommandError("Files are in different branches")
 
350
        other_paths = _relative_paths_in_tree(working_tree, other_paths)
361
351
    specific_files.extend(other_paths)
362
352
    if len(specific_files) == 0:
363
353
        specific_files = None
364
 
        if (working_tree is not None and working_tree.supports_views()
365
 
            and apply_view):
366
 
            view_files = working_tree.views.lookup_view()
367
 
            if view_files:
368
 
                specific_files = view_files
369
 
                view_str = views.view_display_str(view_files)
370
 
                note("*** Ignoring files outside view. View is %s" % view_str)
371
354
 
372
355
    # Get extra trees that ought to be searched for file-ids
373
356
    extra_trees = None
375
358
        extra_trees = (working_tree,)
376
359
    return old_tree, new_tree, specific_files, extra_trees
377
360
 
 
361
 
378
362
def _get_tree_to_diff(spec, tree=None, branch=None, basis_is_default=True):
379
363
    if branch is None and tree is not None:
380
364
        branch = tree.branch
386
370
                return branch.basis_tree()
387
371
        else:
388
372
            return tree
389
 
    return spec.as_tree(branch)
 
373
    if not spec.needs_branch():
 
374
        branch = _mod_branch.Branch.open(spec.get_branch())
 
375
    revision_id = spec.as_revision_id(branch)
 
376
    return branch.repository.revision_tree(revision_id)
 
377
 
 
378
 
 
379
def _relative_paths_in_tree(tree, paths):
 
380
    """Get the relative paths within a working tree.
 
381
 
 
382
    Each path may be either an absolute path or a path relative to the
 
383
    current working directory.
 
384
    """
 
385
    result = []
 
386
    for filename in paths:
 
387
        try:
 
388
            result.append(tree.relpath(osutils.dereference_path(filename)))
 
389
        except errors.PathNotChild:
 
390
            raise errors.BzrCommandError("Files are in different branches")
 
391
    return result
390
392
 
391
393
 
392
394
def show_diff_trees(old_tree, new_tree, to_file, specific_files=None,
440
442
    return timestamp.format_patch_date(mtime)
441
443
 
442
444
 
 
445
def _raise_if_nonexistent(paths, old_tree, new_tree):
 
446
    """Complain if paths are not in either inventory or tree.
 
447
 
 
448
    It's OK with the files exist in either tree's inventory, or 
 
449
    if they exist in the tree but are not versioned.
 
450
    
 
451
    This can be used by operations such as bzr status that can accept
 
452
    unknown or ignored files.
 
453
    """
 
454
    mutter("check paths: %r", paths)
 
455
    if not paths:
 
456
        return
 
457
    s = old_tree.filter_unversioned_files(paths)
 
458
    s = new_tree.filter_unversioned_files(s)
 
459
    s = [path for path in s if not new_tree.has_filename(path)]
 
460
    if s:
 
461
        raise errors.PathsDoNotExist(sorted(s))
 
462
 
 
463
 
 
464
@deprecated_function(one_three)
 
465
def get_prop_change(meta_modified):
 
466
    if meta_modified:
 
467
        return " (properties changed)"
 
468
    else:
 
469
        return  ""
 
470
 
443
471
def get_executable_change(old_is_x, new_is_x):
444
472
    descr = { True:"+x", False:"-x", None:"??" }
445
473
    if old_is_x != new_is_x:
620
648
            return self.CANNOT_DIFF
621
649
        from_label = '%s%s\t%s' % (self.old_label, old_path, old_date)
622
650
        to_label = '%s%s\t%s' % (self.new_label, new_path, new_date)
623
 
        return self.diff_text(from_file_id, to_file_id, from_label, to_label,
624
 
            old_path, new_path)
 
651
        return self.diff_text(from_file_id, to_file_id, from_label, to_label)
625
652
 
626
 
    def diff_text(self, from_file_id, to_file_id, from_label, to_label,
627
 
        from_path=None, to_path=None):
 
653
    def diff_text(self, from_file_id, to_file_id, from_label, to_label):
628
654
        """Diff the content of given files in two trees
629
655
 
630
656
        :param from_file_id: The id of the file in the from tree.  If None,
632
658
        :param to_file_id: The id of the file in the to tree.  This may refer
633
659
            to a different file from from_file_id.  If None,
634
660
            the file is not present in the to tree.
635
 
        :param from_path: The path in the from tree or None if unknown.
636
 
        :param to_path: The path in the to tree or None if unknown.
637
661
        """
638
 
        def _get_text(tree, file_id, path):
 
662
        def _get_text(tree, file_id):
639
663
            if file_id is not None:
640
 
                return tree.get_file(file_id, path).readlines()
 
664
                return tree.get_file(file_id).readlines()
641
665
            else:
642
666
                return []
643
667
        try:
644
 
            from_text = _get_text(self.old_tree, from_file_id, from_path)
645
 
            to_text = _get_text(self.new_tree, to_file_id, to_path)
 
668
            from_text = _get_text(self.old_tree, from_file_id)
 
669
            to_text = _get_text(self.new_tree, to_file_id)
646
670
            self.text_differ(from_label, from_text, to_label, to_text,
647
671
                             self.to_file)
648
672
        except errors.BinaryFile:
658
682
                 path_encoding='utf-8'):
659
683
        DiffPath.__init__(self, old_tree, new_tree, to_file, path_encoding)
660
684
        self.command_template = command_template
661
 
        self._root = osutils.mkdtemp(prefix='bzr-diff-')
 
685
        self._root = tempfile.mkdtemp(prefix='bzr-diff-')
662
686
 
663
687
    @classmethod
664
688
    def from_string(klass, command_string, old_tree, new_tree, to_file,
735
759
        return old_disk_path, new_disk_path
736
760
 
737
761
    def finish(self):
738
 
        try:
739
 
            osutils.rmtree(self._root)
740
 
        except OSError, e:
741
 
            if e.errno != errno.ENOENT:
742
 
                mutter("The temporary directory \"%s\" was not "
743
 
                        "cleanly removed: %s." % (self._root, e))
 
762
        osutils.rmtree(self._root)
744
763
 
745
764
    def diff(self, file_id, old_path, new_path, old_kind, new_kind):
746
765
        if (old_kind, new_kind) != ('file', 'file'):
891
910
                self.to_file.write("=== modified %s '%s'%s\n" % (kind[0],
892
911
                                   newpath_encoded, prop_str))
893
912
            if changed_content:
894
 
                self._diff(file_id, oldpath, newpath, kind[0], kind[1])
 
913
                self.diff(file_id, oldpath, newpath)
895
914
                has_changes = 1
896
915
            if renamed:
897
916
                has_changes = 1
912
931
            new_kind = self.new_tree.kind(file_id)
913
932
        except (errors.NoSuchId, errors.NoSuchFile):
914
933
            new_kind = None
915
 
        self._diff(file_id, old_path, new_path, old_kind, new_kind)
916
 
 
917
 
 
918
 
    def _diff(self, file_id, old_path, new_path, old_kind, new_kind):
 
934
 
919
935
        result = DiffPath._diff_many(self.differs, file_id, old_path,
920
936
                                       new_path, old_kind, new_kind)
921
937
        if result is DiffPath.CANNOT_DIFF: