/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/transform.py

  • Committer: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
    annotate,
26
26
    bencode,
27
27
    bzrdir,
28
 
    commit,
29
28
    delta,
30
29
    errors,
31
30
    inventory,
315
314
 
316
315
    def delete_contents(self, trans_id):
317
316
        """Schedule the contents of a path entry for deletion"""
318
 
        kind = self.tree_kind(trans_id)
319
 
        if kind is not None:
320
 
            self._removed_contents.add(trans_id)
 
317
        # Ensure that the object exists in the WorkingTree, this will raise an
 
318
        # exception if there is a problem
 
319
        self.tree_kind(trans_id)
 
320
        self._removed_contents.add(trans_id)
321
321
 
322
322
    def cancel_deletion(self, trans_id):
323
323
        """Cancel a scheduled deletion"""
388
388
        changed_kind = set(self._removed_contents)
389
389
        changed_kind.intersection_update(self._new_contents)
390
390
        changed_kind.difference_update(new_ids)
391
 
        changed_kind = (t for t in changed_kind
392
 
                        if self.tree_kind(t) != self.final_kind(t))
 
391
        changed_kind = (t for t in changed_kind if self.tree_kind(t) !=
 
392
                        self.final_kind(t))
393
393
        new_ids.update(changed_kind)
394
394
        return sorted(FinalPaths(self).get_paths(new_ids))
395
395
 
396
396
    def final_kind(self, trans_id):
397
397
        """Determine the final file kind, after any changes applied.
398
398
 
399
 
        :return: None if the file does not exist/has no contents.  (It is
400
 
            conceivable that a path would be created without the corresponding
401
 
            contents insertion command)
 
399
        Raises NoSuchFile if the file does not exist/has no contents.
 
400
        (It is conceivable that a path would be created without the
 
401
        corresponding contents insertion command)
402
402
        """
403
403
        if trans_id in self._new_contents:
404
404
            return self._new_contents[trans_id]
405
405
        elif trans_id in self._removed_contents:
406
 
            return None
 
406
            raise NoSuchFile(None)
407
407
        else:
408
408
            return self.tree_kind(trans_id)
409
409
 
595
595
        """
596
596
        conflicts = []
597
597
        for trans_id in self._new_id.iterkeys():
598
 
            kind = self.final_kind(trans_id)
599
 
            if kind is None:
 
598
            try:
 
599
                kind = self.final_kind(trans_id)
 
600
            except NoSuchFile:
600
601
                conflicts.append(('versioning no contents', trans_id))
601
602
                continue
602
603
            if not InventoryEntry.versionable_kind(kind):
616
617
            if self.final_file_id(trans_id) is None:
617
618
                conflicts.append(('unversioned executability', trans_id))
618
619
            else:
619
 
                if self.final_kind(trans_id) != "file":
 
620
                try:
 
621
                    non_file = self.final_kind(trans_id) != "file"
 
622
                except NoSuchFile:
 
623
                    non_file = True
 
624
                if non_file is True:
620
625
                    conflicts.append(('non-file executability', trans_id))
621
626
        return conflicts
622
627
 
624
629
        """Check for overwrites (not permitted on Win32)"""
625
630
        conflicts = []
626
631
        for trans_id in self._new_contents:
627
 
            if self.tree_kind(trans_id) is None:
 
632
            try:
 
633
                self.tree_kind(trans_id)
 
634
            except NoSuchFile:
628
635
                continue
629
636
            if trans_id not in self._removed_contents:
630
637
                conflicts.append(('overwrite', trans_id,
644
651
            last_name = None
645
652
            last_trans_id = None
646
653
            for name, trans_id in name_ids:
647
 
                kind = self.final_kind(trans_id)
 
654
                try:
 
655
                    kind = self.final_kind(trans_id)
 
656
                except NoSuchFile:
 
657
                    kind = None
648
658
                file_id = self.final_file_id(trans_id)
649
659
                if kind is None and file_id is None:
650
660
                    continue
676
686
                continue
677
687
            if not self._any_contents(children):
678
688
                continue
679
 
            kind = self.final_kind(parent_id)
 
689
            for child in children:
 
690
                try:
 
691
                    self.final_kind(child)
 
692
                except NoSuchFile:
 
693
                    continue
 
694
            try:
 
695
                kind = self.final_kind(parent_id)
 
696
            except NoSuchFile:
 
697
                kind = None
680
698
            if kind is None:
681
699
                conflicts.append(('missing parent', parent_id))
682
700
            elif kind != "directory":
686
704
    def _any_contents(self, trans_ids):
687
705
        """Return true if any of the trans_ids, will have contents."""
688
706
        for trans_id in trans_ids:
689
 
            if self.final_kind(trans_id) is not None:
690
 
                return True
 
707
            try:
 
708
                kind = self.final_kind(trans_id)
 
709
            except NoSuchFile:
 
710
                continue
 
711
            return True
691
712
        return False
692
713
 
693
714
    def _set_executability(self, path, trans_id):
823
844
        Return a (name, parent, kind, executable) tuple
824
845
        """
825
846
        to_name = self.final_name(to_trans_id)
826
 
        to_kind = self.final_kind(to_trans_id)
 
847
        try:
 
848
            to_kind = self.final_kind(to_trans_id)
 
849
        except NoSuchFile:
 
850
            to_kind = None
827
851
        to_parent = self.final_file_id(self.final_parent(to_trans_id))
828
852
        if to_trans_id in self._new_executability:
829
853
            to_executable = self._new_executability[to_trans_id]
903
927
        """
904
928
        return _PreviewTree(self)
905
929
 
906
 
    def commit(self, branch, message, merge_parents=None, strict=False,
907
 
               timestamp=None, timezone=None, committer=None, authors=None,
908
 
               revprops=None, revision_id=None):
 
930
    def commit(self, branch, message, merge_parents=None, strict=False):
909
931
        """Commit the result of this TreeTransform to a branch.
910
932
 
911
933
        :param branch: The branch to commit to.
912
934
        :param message: The message to attach to the commit.
913
 
        :param merge_parents: Additional parent revision-ids specified by
914
 
            pending merges.
915
 
        :param strict: If True, abort the commit if there are unversioned
916
 
            files.
917
 
        :param timestamp: if not None, seconds-since-epoch for the time and
918
 
            date.  (May be a float.)
919
 
        :param timezone: Optional timezone for timestamp, as an offset in
920
 
            seconds.
921
 
        :param committer: Optional committer in email-id format.
922
 
            (e.g. "J Random Hacker <jrandom@example.com>")
923
 
        :param authors: Optional list of authors in email-id format.
924
 
        :param revprops: Optional dictionary of revision properties.
925
 
        :param revision_id: Optional revision id.  (Specifying a revision-id
926
 
            may reduce performance for some non-native formats.)
 
935
        :param merge_parents: Additional parents specified by pending merges.
927
936
        :return: The revision_id of the revision committed.
928
937
        """
929
938
        self._check_malformed()
946
955
        if self._tree.get_revision_id() != last_rev_id:
947
956
            raise ValueError('TreeTransform not based on branch basis: %s' %
948
957
                             self._tree.get_revision_id())
949
 
        revprops = commit.Commit.update_revprops(revprops, branch, authors)
950
 
        builder = branch.get_commit_builder(parent_ids,
951
 
                                            timestamp=timestamp,
952
 
                                            timezone=timezone,
953
 
                                            committer=committer,
954
 
                                            revprops=revprops,
955
 
                                            revision_id=revision_id)
 
958
        builder = branch.get_commit_builder(parent_ids)
956
959
        preview = self.get_preview_tree()
957
960
        list(builder.record_iter_changes(preview, last_rev_id,
958
961
                                         self.iter_changes()))
1157
1160
            if trans_id not in self._new_contents:
1158
1161
                continue
1159
1162
            new_path = self._limbo_name(trans_id)
1160
 
            os.rename(old_path, new_path)
 
1163
            osutils.rename(old_path, new_path)
1161
1164
            for descendant in self._limbo_descendants(trans_id):
1162
1165
                desc_path = self._limbo_files[descendant]
1163
1166
                desc_path = new_path + desc_path[len(old_path):]
1394
1397
    def tree_kind(self, trans_id):
1395
1398
        """Determine the file kind in the working tree.
1396
1399
 
1397
 
        :returns: The file kind or None if the file does not exist
 
1400
        Raises NoSuchFile if the file does not exist
1398
1401
        """
1399
1402
        path = self._tree_id_paths.get(trans_id)
1400
1403
        if path is None:
1401
 
            return None
 
1404
            raise NoSuchFile(None)
1402
1405
        try:
1403
1406
            return file_kind(self._tree.abspath(path))
1404
 
        except errors.NoSuchFile:
1405
 
            return None
 
1407
        except OSError, e:
 
1408
            if e.errno != errno.ENOENT:
 
1409
                raise
 
1410
            else:
 
1411
                raise NoSuchFile(path)
1406
1412
 
1407
1413
    def _set_mode(self, trans_id, mode_id, typefunc):
1408
1414
        """Set the mode of new file contents.
1577
1583
                if file_id is None:
1578
1584
                    continue
1579
1585
                needs_entry = False
1580
 
                kind = self.final_kind(trans_id)
1581
 
                if kind is None:
 
1586
                try:
 
1587
                    kind = self.final_kind(trans_id)
 
1588
                except NoSuchFile:
1582
1589
                    kind = self._tree.stored_kind(file_id)
1583
1590
                parent_trans_id = self.final_parent(trans_id)
1584
1591
                parent_file_id = new_path_file_ids.get(parent_trans_id)
1628
1635
                      or trans_id in self._new_parent):
1629
1636
                    try:
1630
1637
                        mover.rename(full_path, self._limbo_name(trans_id))
1631
 
                    except errors.TransformRenameFailed, e:
 
1638
                    except OSError, e:
1632
1639
                        if e.errno != errno.ENOENT:
1633
1640
                            raise
1634
1641
                    else:
1659
1666
                if trans_id in self._needs_rename:
1660
1667
                    try:
1661
1668
                        mover.rename(self._limbo_name(trans_id), full_path)
1662
 
                    except errors.TransformRenameFailed, e:
 
1669
                    except OSError, e:
1663
1670
                        # We may be renaming a dangling inventory id
1664
1671
                        if e.errno != errno.ENOENT:
1665
1672
                            raise
1696
1703
    def tree_kind(self, trans_id):
1697
1704
        path = self._tree_id_paths.get(trans_id)
1698
1705
        if path is None:
1699
 
            return None
 
1706
            raise NoSuchFile(None)
1700
1707
        file_id = self._tree.path2id(path)
1701
 
        try:
1702
 
            return self._tree.kind(file_id)
1703
 
        except errors.NoSuchFile:
1704
 
            return None
 
1708
        return self._tree.kind(file_id)
1705
1709
 
1706
1710
    def _set_mode(self, trans_id, mode_id, typefunc):
1707
1711
        """Set the mode of new file contents.
1766
1770
        parent_keys = [(file_id, self._file_revision(t, file_id)) for t in
1767
1771
                       self._iter_parent_trees()]
1768
1772
        vf.add_lines((file_id, tree_revision), parent_keys,
1769
 
                     self.get_file_lines(file_id))
 
1773
                     self.get_file(file_id).readlines())
1770
1774
        repo = self._get_repository()
1771
1775
        base_vf = repo.texts
1772
1776
        if base_vf not in vf.fallback_versionedfiles:
1794
1798
            executable = self.is_executable(file_id, path)
1795
1799
        return kind, executable, None
1796
1800
 
1797
 
    def is_locked(self):
1798
 
        return False
1799
 
 
1800
1801
    def lock_read(self):
1801
1802
        # Perhaps in theory, this should lock the TreeTransform?
1802
 
        return self
 
1803
        pass
1803
1804
 
1804
1805
    def unlock(self):
1805
1806
        pass
1903
1904
            if (specific_file_ids is not None
1904
1905
                and file_id not in specific_file_ids):
1905
1906
                continue
1906
 
            kind = self._transform.final_kind(trans_id)
1907
 
            if kind is None:
 
1907
            try:
 
1908
                kind = self._transform.final_kind(trans_id)
 
1909
            except NoSuchFile:
1908
1910
                kind = self._transform._tree.stored_kind(file_id)
1909
1911
            new_entry = inventory.make_entry(
1910
1912
                kind,
2142
2144
                path_from_root = self._final_paths.get_path(child_id)
2143
2145
                basename = self._transform.final_name(child_id)
2144
2146
                file_id = self._transform.final_file_id(child_id)
2145
 
                kind  = self._transform.final_kind(child_id)
2146
 
                if kind is not None:
 
2147
                try:
 
2148
                    kind = self._transform.final_kind(child_id)
2147
2149
                    versioned_kind = kind
2148
 
                else:
 
2150
                except NoSuchFile:
2149
2151
                    kind = 'unknown'
2150
2152
                    versioned_kind = self._transform._tree.stored_kind(file_id)
2151
2153
                if versioned_kind == 'directory':
2264
2266
    for num, _unused in enumerate(wt.all_file_ids()):
2265
2267
        if num > 0:  # more than just a root
2266
2268
            raise errors.WorkingTreeAlreadyPopulated(base=wt.basedir)
 
2269
    existing_files = set()
 
2270
    for dir, files in wt.walkdirs():
 
2271
        existing_files.update(f[0] for f in files)
2267
2272
    file_trans_id = {}
2268
2273
    top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
2269
2274
    pp = ProgressPhase("Build phase", 2, top_pb)
2293
2298
                precomputed_delta = []
2294
2299
            else:
2295
2300
                precomputed_delta = None
2296
 
            # Check if tree inventory has content. If so, we populate
2297
 
            # existing_files with the directory content. If there are no
2298
 
            # entries we skip populating existing_files as its not used.
2299
 
            # This improves performance and unncessary work on large
2300
 
            # directory trees. (#501307)
2301
 
            if total > 0:
2302
 
                existing_files = set()
2303
 
                for dir, files in wt.walkdirs():
2304
 
                    existing_files.update(f[0] for f in files)
2305
2301
            for num, (tree_path, entry) in \
2306
2302
                enumerate(tree.inventory.iter_entries_by_dir()):
2307
2303
                pb.update("Building tree", num - len(deferred_contents), total)
2439
2435
    if entry.kind == "directory":
2440
2436
        return True
2441
2437
    if entry.kind == "file":
2442
 
        f = file(target_path, 'rb')
2443
 
        try:
2444
 
            if tree.get_file_text(file_id) == f.read():
2445
 
                return True
2446
 
        finally:
2447
 
            f.close()
 
2438
        if tree.get_file(file_id).read() == file(target_path, 'rb').read():
 
2439
            return True
2448
2440
    elif entry.kind == "symlink":
2449
2441
        if tree.get_symlink_target(file_id) == os.readlink(target_path):
2450
2442
            return True
2502
2494
        raise errors.BadFileKindError(name, kind)
2503
2495
 
2504
2496
 
 
2497
@deprecated_function(deprecated_in((1, 9, 0)))
 
2498
def create_by_entry(tt, entry, tree, trans_id, lines=None, mode_id=None):
 
2499
    """Create new file contents according to an inventory entry.
 
2500
 
 
2501
    DEPRECATED.  Use create_from_tree instead.
 
2502
    """
 
2503
    if entry.kind == "file":
 
2504
        if lines is None:
 
2505
            lines = tree.get_file(entry.file_id).readlines()
 
2506
        tt.create_file(lines, trans_id, mode_id=mode_id)
 
2507
    elif entry.kind == "symlink":
 
2508
        tt.create_symlink(tree.get_symlink_target(entry.file_id), trans_id)
 
2509
    elif entry.kind == "directory":
 
2510
        tt.create_directory(trans_id)
 
2511
 
 
2512
 
2505
2513
def create_from_tree(tt, trans_id, tree, file_id, bytes=None,
2506
2514
    filter_tree_path=None):
2507
2515
    """Create new file contents according to tree contents.
2892
2900
    def rename(self, from_, to):
2893
2901
        """Rename a file from one path to another."""
2894
2902
        try:
2895
 
            os.rename(from_, to)
 
2903
            osutils.rename(from_, to)
2896
2904
        except OSError, e:
2897
2905
            if e.errno in (errno.EEXIST, errno.ENOTEMPTY):
2898
2906
                raise errors.FileExists(to, str(e))
2899
 
            # normal OSError doesn't include filenames so it's hard to see where
2900
 
            # the problem is, see https://bugs.launchpad.net/bzr/+bug/491763
2901
 
            raise errors.TransformRenameFailed(from_, to, str(e), e.errno)
 
2907
            raise
2902
2908
        self.past_renames.append((from_, to))
2903
2909
 
2904
2910
    def pre_delete(self, from_, to):
2914
2920
    def rollback(self):
2915
2921
        """Reverse all renames that have been performed"""
2916
2922
        for from_, to in reversed(self.past_renames):
2917
 
            try:
2918
 
                os.rename(to, from_)
2919
 
            except OSError, e:
2920
 
                raise errors.TransformRenameFailed(to, from_, str(e), e.errno)                
 
2923
            osutils.rename(to, from_)
2921
2924
        # after rollback, don't reuse _FileMover
2922
2925
        past_renames = None
2923
2926
        pending_deletions = None