~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transform.py

(jelmer) Deprecate Repository.iter_reverse_revision_history(). (Jelmer
 Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
from bzrlib import (
31
31
    annotate,
32
32
    bencode,
33
 
    controldir,
 
33
    bzrdir,
34
34
    commit,
35
 
    conflicts,
36
35
    delta,
 
36
    errors,
37
37
    inventory,
38
38
    multiparent,
39
39
    osutils,
41
41
    ui,
42
42
    urlutils,
43
43
    )
44
 
from bzrlib.i18n import gettext
45
44
""")
46
 
from bzrlib.errors import (DuplicateKey, MalformedTransform,
 
45
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,
47
46
                           ReusingTransform, CantMoveRoot,
48
47
                           ExistingLimbo, ImmortalLimbo, NoFinalPath,
49
48
                           UnableCreateSymlink)
226
225
        This means that the old root trans-id becomes obsolete, so it is
227
226
        recommended only to invoke this after the root trans-id has become
228
227
        irrelevant.
229
 
 
230
228
        """
231
229
        new_roots = [k for k, v in self._new_parent.iteritems() if v is
232
230
                     ROOT_PARENT]
238
236
            self._new_root = new_roots[0]
239
237
            return
240
238
        old_new_root = new_roots[0]
 
239
        # TODO: What to do if a old_new_root is present, but self._new_root is
 
240
        #       not listed as being removed? This code explicitly unversions
 
241
        #       the old root and versions it with the new file_id. Though that
 
242
        #       seems like an incomplete delta
 
243
 
241
244
        # unversion the new root's directory.
242
 
        if self.final_kind(self._new_root) is None:
243
 
            file_id = self.final_file_id(old_new_root)
244
 
        else:
245
 
            file_id = self.final_file_id(self._new_root)
 
245
        file_id = self.final_file_id(old_new_root)
246
246
        if old_new_root in self._new_id:
247
247
            self.cancel_versioning(old_new_root)
248
248
        else:
561
561
        for trans_id in self._removed_id:
562
562
            file_id = self.tree_file_id(trans_id)
563
563
            if file_id is not None:
564
 
                if self._tree.stored_kind(file_id) == 'directory':
 
564
                # XXX: This seems like something that should go via a different
 
565
                #      indirection.
 
566
                if self._tree.inventory[file_id].kind == 'directory':
565
567
                    parents.append(trans_id)
566
568
            elif self.tree_kind(trans_id) == 'directory':
567
569
                parents.append(trans_id)
776
778
                    to_mode |= 0010 & ~umask
777
779
            else:
778
780
                to_mode = current_mode & ~0111
779
 
            osutils.chmod_if_possible(abspath, to_mode)
 
781
            os.chmod(abspath, to_mode)
780
782
 
781
783
    def _new_entry(self, name, parent_id, file_id):
782
784
        """Helper function to create a new filesystem entry."""
1555
1557
        try:
1556
1558
            limbodir = urlutils.local_path_from_url(
1557
1559
                tree._transport.abspath('limbo'))
1558
 
            osutils.ensure_empty_directory_exists(
1559
 
                limbodir,
1560
 
                errors.ExistingLimbo)
 
1560
            try:
 
1561
                os.mkdir(limbodir)
 
1562
            except OSError, e:
 
1563
                if e.errno == errno.EEXIST:
 
1564
                    raise ExistingLimbo(limbodir)
1561
1565
            deletiondir = urlutils.local_path_from_url(
1562
1566
                tree._transport.abspath('pending-deletion'))
1563
 
            osutils.ensure_empty_directory_exists(
1564
 
                deletiondir,
1565
 
                errors.ExistingPendingDeletion)
 
1567
            try:
 
1568
                os.mkdir(deletiondir)
 
1569
            except OSError, e:
 
1570
                if e.errno == errno.EEXIST:
 
1571
                    raise errors.ExistingPendingDeletion(deletiondir)
1566
1572
        except:
1567
1573
            tree.unlock()
1568
1574
            raise
1631
1637
            else:
1632
1638
                raise
1633
1639
        if typefunc(mode):
1634
 
            osutils.chmod_if_possible(self._limbo_name(trans_id), mode)
 
1640
            os.chmod(self._limbo_name(trans_id), mode)
1635
1641
 
1636
1642
    def iter_tree_children(self, parent_id):
1637
1643
        """Iterate through the entry's tree children, if any"""
1720
1726
        child_pb = ui.ui_factory.nested_progress_bar()
1721
1727
        try:
1722
1728
            if precomputed_delta is None:
1723
 
                child_pb.update(gettext('Apply phase'), 0, 2)
 
1729
                child_pb.update('Apply phase', 0, 2)
1724
1730
                inventory_delta = self._generate_inventory_delta()
1725
1731
                offset = 1
1726
1732
            else:
1731
1737
            else:
1732
1738
                mover = _mover
1733
1739
            try:
1734
 
                child_pb.update(gettext('Apply phase'), 0 + offset, 2 + offset)
 
1740
                child_pb.update('Apply phase', 0 + offset, 2 + offset)
1735
1741
                self._apply_removals(mover)
1736
 
                child_pb.update(gettext('Apply phase'), 1 + offset, 2 + offset)
 
1742
                child_pb.update('Apply phase', 1 + offset, 2 + offset)
1737
1743
                modified_paths = self._apply_insertions(mover)
1738
1744
            except:
1739
1745
                mover.rollback()
1742
1748
                mover.apply_deletions()
1743
1749
        finally:
1744
1750
            child_pb.finished()
1745
 
        if self.final_file_id(self.root) is None:
1746
 
            inventory_delta = [e for e in inventory_delta if e[0] != '']
1747
1751
        self._tree.apply_inventory_delta(inventory_delta)
1748
1752
        self._apply_observed_sha1s()
1749
1753
        self._done = True
1759
1763
        try:
1760
1764
            for num, trans_id in enumerate(self._removed_id):
1761
1765
                if (num % 10) == 0:
1762
 
                    child_pb.update(gettext('removing file'), num, total_entries)
 
1766
                    child_pb.update('removing file', num, total_entries)
1763
1767
                if trans_id == self._new_root:
1764
1768
                    file_id = self._tree.get_root_id()
1765
1769
                else:
1777
1781
            final_kinds = {}
1778
1782
            for num, (path, trans_id) in enumerate(new_paths):
1779
1783
                if (num % 10) == 0:
1780
 
                    child_pb.update(gettext('adding file'),
 
1784
                    child_pb.update('adding file',
1781
1785
                                    num + len(self._removed_id), total_entries)
1782
1786
                file_id = new_path_file_ids[trans_id]
1783
1787
                if file_id is None:
1827
1831
                # do not attempt to move root into a subdirectory of itself.
1828
1832
                if path == '':
1829
1833
                    continue
1830
 
                child_pb.update(gettext('removing file'), num, len(tree_paths))
 
1834
                child_pb.update('removing file', num, len(tree_paths))
1831
1835
                full_path = self._tree.abspath(path)
1832
1836
                if trans_id in self._removed_contents:
1833
1837
                    delete_path = os.path.join(self._deletiondir, trans_id)
1862
1866
        try:
1863
1867
            for num, (path, trans_id) in enumerate(new_paths):
1864
1868
                if (num % 10) == 0:
1865
 
                    child_pb.update(gettext('adding file'), num, len(new_paths))
 
1869
                    child_pb.update('adding file', num, len(new_paths))
1866
1870
                full_path = self._tree.abspath(path)
1867
1871
                if trans_id in self._needs_rename:
1868
1872
                    try:
2252
2256
        else:
2253
2257
            return None
2254
2258
 
2255
 
    def get_file_verifier(self, file_id, path=None, stat_value=None):
2256
 
        trans_id = self._transform.trans_id_file_id(file_id)
2257
 
        kind = self._transform._new_contents.get(trans_id)
2258
 
        if kind is None:
2259
 
            return self._transform._tree.get_file_verifier(file_id)
2260
 
        if kind == 'file':
2261
 
            fileobj = self.get_file(file_id)
2262
 
            try:
2263
 
                return ("SHA1", sha_file(fileobj))
2264
 
            finally:
2265
 
                fileobj.close()
2266
 
 
2267
2259
    def get_file_sha1(self, file_id, path=None, stat_value=None):
2268
2260
        trans_id = self._transform.trans_id_file_id(file_id)
2269
2261
        kind = self._transform._new_contents.get(trans_id)
2540
2532
    file_trans_id = {}
2541
2533
    top_pb = ui.ui_factory.nested_progress_bar()
2542
2534
    pp = ProgressPhase("Build phase", 2, top_pb)
2543
 
    if tree.get_root_id() is not None:
 
2535
    if tree.inventory.root is not None:
2544
2536
        # This is kind of a hack: we should be altering the root
2545
2537
        # as part of the regular tree shape diff logic.
2546
2538
        # The conditional test here is to avoid doing an
2561
2553
        try:
2562
2554
            deferred_contents = []
2563
2555
            num = 0
2564
 
            total = len(tree.all_file_ids())
 
2556
            total = len(tree.inventory)
2565
2557
            if delta_from_tree:
2566
2558
                precomputed_delta = []
2567
2559
            else:
2576
2568
                for dir, files in wt.walkdirs():
2577
2569
                    existing_files.update(f[0] for f in files)
2578
2570
            for num, (tree_path, entry) in \
2579
 
                enumerate(tree.iter_entries_by_dir()):
2580
 
                pb.update(gettext("Building tree"), num - len(deferred_contents), total)
 
2571
                enumerate(tree.inventory.iter_entries_by_dir()):
 
2572
                pb.update("Building tree", num - len(deferred_contents), total)
2581
2573
                if entry.parent_id is None:
2582
2574
                    continue
2583
2575
                reparent = False
2589
2581
                    kind = file_kind(target_path)
2590
2582
                    if kind == "directory":
2591
2583
                        try:
2592
 
                            controldir.ControlDir.open(target_path)
 
2584
                            bzrdir.BzrDir.open(target_path)
2593
2585
                        except errors.NotBranchError:
2594
2586
                            pass
2595
2587
                        else:
2667
2659
                new_desired_files.append((file_id,
2668
2660
                    (trans_id, tree_path, text_sha1)))
2669
2661
                continue
2670
 
            pb.update(gettext('Adding file contents'), count + offset, total)
 
2662
            pb.update('Adding file contents', count + offset, total)
2671
2663
            if hardlink:
2672
2664
                tt.create_hardlink(accelerator_tree.abspath(accelerator_path),
2673
2665
                                   trans_id)
2694
2686
            contents = filtered_output_bytes(contents, filters,
2695
2687
                ContentFilterContext(tree_path, tree))
2696
2688
        tt.create_file(contents, trans_id, sha1=text_sha1)
2697
 
        pb.update(gettext('Adding file contents'), count + offset, total)
 
2689
        pb.update('Adding file contents', count + offset, total)
2698
2690
 
2699
2691
 
2700
2692
def _reparent_children(tt, old_parent, new_parent):
2832
2824
            return new_name
2833
2825
 
2834
2826
 
 
2827
def _entry_changes(file_id, entry, working_tree):
 
2828
    """Determine in which ways the inventory entry has changed.
 
2829
 
 
2830
    Returns booleans: has_contents, content_mod, meta_mod
 
2831
    has_contents means there are currently contents, but they differ
 
2832
    contents_mod means contents need to be modified
 
2833
    meta_mod means the metadata needs to be modified
 
2834
    """
 
2835
    cur_entry = working_tree.inventory[file_id]
 
2836
    try:
 
2837
        working_kind = working_tree.kind(file_id)
 
2838
        has_contents = True
 
2839
    except NoSuchFile:
 
2840
        has_contents = False
 
2841
        contents_mod = True
 
2842
        meta_mod = False
 
2843
    if has_contents is True:
 
2844
        if entry.kind != working_kind:
 
2845
            contents_mod, meta_mod = True, False
 
2846
        else:
 
2847
            cur_entry._read_tree_state(working_tree.id2path(file_id),
 
2848
                                       working_tree)
 
2849
            contents_mod, meta_mod = entry.detect_changes(cur_entry)
 
2850
            cur_entry._forget_tree_state()
 
2851
    return has_contents, contents_mod, meta_mod
 
2852
 
 
2853
 
2835
2854
def revert(working_tree, target_tree, filenames, backups=False,
2836
2855
           pb=None, change_reporter=None):
2837
2856
    """Revert a working tree's contents to those of a target tree."""
2919
2938
                        if basis_tree is None:
2920
2939
                            basis_tree = working_tree.basis_tree()
2921
2940
                            basis_tree.lock_read()
2922
 
                        if basis_tree.has_id(file_id):
 
2941
                        if file_id in basis_tree:
2923
2942
                            if wt_sha1 != basis_tree.get_file_sha1(file_id):
2924
2943
                                keep_content = True
2925
2944
                        elif target_kind is None and not target_versioned:
2955
2974
                        basis_tree = working_tree.basis_tree()
2956
2975
                        basis_tree.lock_read()
2957
2976
                    new_sha1 = target_tree.get_file_sha1(file_id)
2958
 
                    if (basis_tree.has_id(file_id) and
2959
 
                        new_sha1 == basis_tree.get_file_sha1(file_id)):
 
2977
                    if (file_id in basis_tree and new_sha1 ==
 
2978
                        basis_tree.get_file_sha1(file_id)):
2960
2979
                        if file_id in merge_modified:
2961
2980
                            del merge_modified[file_id]
2962
2981
                    else:
3014
3033
    pb = ui.ui_factory.nested_progress_bar()
3015
3034
    try:
3016
3035
        for n in range(10):
3017
 
            pb.update(gettext('Resolution pass'), n+1, 10)
 
3036
            pb.update('Resolution pass', n+1, 10)
3018
3037
            conflicts = tt.find_conflicts()
3019
3038
            if len(conflicts) == 0:
3020
3039
                return new_conflicts
3044
3063
                existing_file, new_file = conflict[2], conflict[1]
3045
3064
            else:
3046
3065
                existing_file, new_file = conflict[1], conflict[2]
3047
 
            new_name = tt.final_name(existing_file) + '.moved'
 
3066
            new_name = tt.final_name(existing_file)+'.moved'
3048
3067
            tt.adjust_path(new_name, final_parent, existing_file)
3049
3068
            new_conflicts.add((c_type, 'Moved existing file to',
3050
3069
                               existing_file, new_file))
3113
3132
        elif c_type == 'unversioned parent':
3114
3133
            file_id = tt.inactive_file_id(conflict[1])
3115
3134
            # special-case the other tree root (move its children instead)
3116
 
            if path_tree and path_tree.has_id(file_id):
 
3135
            if path_tree and file_id in path_tree:
3117
3136
                if path_tree.path2id('') == file_id:
3118
3137
                    # This is the root entry, skip it
3119
3138
                    continue
3137
3156
 
3138
3157
def cook_conflicts(raw_conflicts, tt):
3139
3158
    """Generate a list of cooked conflicts, sorted by file path"""
 
3159
    from bzrlib.conflicts import Conflict
3140
3160
    conflict_iter = iter_cook_conflicts(raw_conflicts, tt)
3141
 
    return sorted(conflict_iter, key=conflicts.Conflict.sort_key)
 
3161
    return sorted(conflict_iter, key=Conflict.sort_key)
3142
3162
 
3143
3163
 
3144
3164
def iter_cook_conflicts(raw_conflicts, tt):
 
3165
    from bzrlib.conflicts import Conflict
3145
3166
    fp = FinalPaths(tt)
3146
3167
    for conflict in raw_conflicts:
3147
3168
        c_type = conflict[0]
3149
3170
        modified_path = fp.get_path(conflict[2])
3150
3171
        modified_id = tt.final_file_id(conflict[2])
3151
3172
        if len(conflict) == 3:
3152
 
            yield conflicts.Conflict.factory(
3153
 
                c_type, action=action, path=modified_path, file_id=modified_id)
 
3173
            yield Conflict.factory(c_type, action=action, path=modified_path,
 
3174
                                     file_id=modified_id)
3154
3175
 
3155
3176
        else:
3156
3177
            conflicting_path = fp.get_path(conflict[3])
3157
3178
            conflicting_id = tt.final_file_id(conflict[3])
3158
 
            yield conflicts.Conflict.factory(
3159
 
                c_type, action=action, path=modified_path,
3160
 
                file_id=modified_id,
3161
 
                conflict_path=conflicting_path,
3162
 
                conflict_file_id=conflicting_id)
 
3179
            yield Conflict.factory(c_type, action=action, path=modified_path,
 
3180
                                   file_id=modified_id,
 
3181
                                   conflict_path=conflicting_path,
 
3182
                                   conflict_file_id=conflicting_id)
3163
3183
 
3164
3184
 
3165
3185
class _FileMover(object):