~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transform.py

  • Committer: Vincent Ladeuil
  • Date: 2012-03-14 10:17:12 UTC
  • mto: This revision was merged to the branch mainline in revision 6501.
  • Revision ID: v.ladeuil+lp@free.fr-20120314101712-8m19vlkis5yr0xtp
Yet more deprecated code removals

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
 
17
from __future__ import absolute_import
 
18
 
17
19
import os
18
20
import errno
19
21
from stat import S_ISREG, S_IEXEC
20
22
import time
21
23
 
22
24
from bzrlib import (
 
25
    config as _mod_config,
23
26
    errors,
24
27
    lazy_import,
25
28
    registry,
30
33
from bzrlib import (
31
34
    annotate,
32
35
    bencode,
33
 
    bzrdir,
 
36
    controldir,
34
37
    commit,
35
38
    conflicts,
36
39
    delta,
37
 
    errors,
38
40
    inventory,
39
41
    multiparent,
40
42
    osutils,
42
44
    ui,
43
45
    urlutils,
44
46
    )
 
47
from bzrlib.i18n import gettext
45
48
""")
46
 
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,
 
49
from bzrlib.errors import (DuplicateKey, MalformedTransform,
47
50
                           ReusingTransform, CantMoveRoot,
48
 
                           ExistingLimbo, ImmortalLimbo, NoFinalPath,
 
51
                           ImmortalLimbo, NoFinalPath,
49
52
                           UnableCreateSymlink)
50
53
from bzrlib.filters import filtered_output_bytes, ContentFilterContext
 
54
from bzrlib.mutabletree import MutableTree
51
55
from bzrlib.osutils import (
52
56
    delete_any,
53
57
    file_kind,
55
59
    pathjoin,
56
60
    sha_file,
57
61
    splitpath,
58
 
    supports_executable,
59
62
    )
60
63
from bzrlib.progress import ProgressPhase
61
64
from bzrlib.symbol_versioning import (
154
157
        """
155
158
        if self._tree is None:
156
159
            return
 
160
        for hook in MutableTree.hooks['post_transform']:
 
161
            hook(self._tree, self)
157
162
        self._tree.unlock()
158
163
        self._tree = None
159
164
 
228
233
        irrelevant.
229
234
 
230
235
        """
231
 
        new_roots = [k for k, v in self._new_parent.iteritems() if v is
 
236
        new_roots = [k for k, v in self._new_parent.iteritems() if v ==
232
237
                     ROOT_PARENT]
233
238
        if len(new_roots) < 1:
234
 
            if self.final_kind(self.root) is None:
235
 
                self.cancel_deletion(self.root)
236
 
            if self.final_file_id(self.root) is None:
237
 
                self.version_file(self.tree_file_id(self.root),
238
 
                                     self.root)
239
239
            return
240
240
        if len(new_roots) != 1:
241
241
            raise ValueError('A tree cannot have two roots!')
243
243
            self._new_root = new_roots[0]
244
244
            return
245
245
        old_new_root = new_roots[0]
246
 
        # TODO: What to do if a old_new_root is present, but self._new_root is
247
 
        #       not listed as being removed? This code explicitly unversions
248
 
        #       the old root and versions it with the new file_id. Though that
249
 
        #       seems like an incomplete delta
250
 
 
251
246
        # unversion the new root's directory.
252
 
        file_id = self.final_file_id(old_new_root)
 
247
        if self.final_kind(self._new_root) is None:
 
248
            file_id = self.final_file_id(old_new_root)
 
249
        else:
 
250
            file_id = self.final_file_id(self._new_root)
253
251
        if old_new_root in self._new_id:
254
252
            self.cancel_versioning(old_new_root)
255
253
        else:
568
566
        for trans_id in self._removed_id:
569
567
            file_id = self.tree_file_id(trans_id)
570
568
            if file_id is not None:
571
 
                # XXX: This seems like something that should go via a different
572
 
                #      indirection.
573
 
                if self._tree.inventory[file_id].kind == 'directory':
 
569
                if self._tree.stored_kind(file_id) == 'directory':
574
570
                    parents.append(trans_id)
575
571
            elif self.tree_kind(trans_id) == 'directory':
576
572
                parents.append(trans_id)
579
575
            # ensure that all children are registered with the transaction
580
576
            list(self.iter_tree_children(parent_id))
581
577
 
582
 
    @deprecated_method(deprecated_in((2, 3, 0)))
583
 
    def has_named_child(self, by_parent, parent_id, name):
584
 
        return self._has_named_child(
585
 
            name, parent_id, known_children=by_parent.get(parent_id, []))
586
 
 
587
578
    def _has_named_child(self, name, parent_id, known_children):
588
579
        """Does a parent already have a name child.
589
580
 
633
624
        for trans_id in self._new_parent:
634
625
            seen = set()
635
626
            parent_id = trans_id
636
 
            while parent_id is not ROOT_PARENT:
 
627
            while parent_id != ROOT_PARENT:
637
628
                seen.add(parent_id)
638
629
                try:
639
630
                    parent_id = self.final_parent(parent_id)
649
640
        """If parent directories are versioned, children must be versioned."""
650
641
        conflicts = []
651
642
        for parent_id, children in by_parent.iteritems():
652
 
            if parent_id is ROOT_PARENT:
 
643
            if parent_id == ROOT_PARENT:
653
644
                continue
654
645
            if self.final_file_id(parent_id) is not None:
655
646
                continue
748
739
        """Children must have a directory parent"""
749
740
        conflicts = []
750
741
        for parent_id, children in by_parent.iteritems():
751
 
            if parent_id is ROOT_PARENT:
 
742
            if parent_id == ROOT_PARENT:
752
743
                continue
753
744
            no_children = True
754
745
            for child_id in children:
770
761
 
771
762
    def _set_executability(self, path, trans_id):
772
763
        """Set the executability of versioned files """
773
 
        if supports_executable():
 
764
        if self._tree._supports_executable():
774
765
            new_executability = self._new_executability[trans_id]
775
766
            abspath = self._tree.abspath(path)
776
767
            current_mode = os.stat(abspath).st_mode
785
776
                    to_mode |= 0010 & ~umask
786
777
            else:
787
778
                to_mode = current_mode & ~0111
788
 
            os.chmod(abspath, to_mode)
 
779
            osutils.chmod_if_possible(abspath, to_mode)
789
780
 
790
781
    def _new_entry(self, name, parent_id, file_id):
791
782
        """Helper function to create a new filesystem entry."""
1240
1231
        finally:
1241
1232
            TreeTransformBase.finalize(self)
1242
1233
 
 
1234
    def _limbo_supports_executable(self):
 
1235
        """Check if the limbo path supports the executable bit."""
 
1236
        # FIXME: Check actual file system capabilities of limbodir
 
1237
        return osutils.supports_executable()
 
1238
 
1243
1239
    def _limbo_name(self, trans_id):
1244
1240
        """Generate the limbo name of a file"""
1245
1241
        limbo_name = self._limbo_files.get(trans_id)
1405
1401
        delete_any(self._limbo_name(trans_id))
1406
1402
 
1407
1403
    def new_orphan(self, trans_id, parent_id):
1408
 
        # FIXME: There is no tree config, so we use the branch one (it's weird
1409
 
        # to define it this way as orphaning can only occur in a working tree,
1410
 
        # but that's all we have (for now). It will find the option in
1411
 
        # locations.conf or bazaar.conf though) -- vila 20100916
1412
 
        conf = self._tree.branch.get_config()
1413
 
        conf_var_name = 'bzr.transform.orphan_policy'
1414
 
        orphan_policy = conf.get_user_option(conf_var_name)
1415
 
        default_policy = orphaning_registry.default_key
1416
 
        if orphan_policy is None:
1417
 
            orphan_policy = default_policy
1418
 
        if orphan_policy not in orphaning_registry:
1419
 
            trace.warning('%s (from %s) is not a known policy, defaulting '
1420
 
                'to %s' % (orphan_policy, conf_var_name, default_policy))
1421
 
            orphan_policy = default_policy
1422
 
        handle_orphan = orphaning_registry.get(orphan_policy)
 
1404
        conf = self._tree.get_config_stack()
 
1405
        handle_orphan = conf.get('bzr.transform.orphan_policy')
1423
1406
        handle_orphan(self, trans_id, parent_id)
1424
1407
 
1425
1408
 
1488
1471
orphaning_registry._set_default_key('conflict')
1489
1472
 
1490
1473
 
 
1474
opt_transform_orphan = _mod_config.RegistryOption(
 
1475
    'bzr.transform.orphan_policy', orphaning_registry,
 
1476
    help='Policy for orphaned files during transform operations.',
 
1477
    invalid='warning')
 
1478
 
 
1479
 
1491
1480
class TreeTransform(DiskTreeTransform):
1492
1481
    """Represent a tree transformation.
1493
1482
 
1564
1553
        try:
1565
1554
            limbodir = urlutils.local_path_from_url(
1566
1555
                tree._transport.abspath('limbo'))
1567
 
            try:
1568
 
                os.mkdir(limbodir)
1569
 
            except OSError, e:
1570
 
                if e.errno == errno.EEXIST:
1571
 
                    raise ExistingLimbo(limbodir)
 
1556
            osutils.ensure_empty_directory_exists(
 
1557
                limbodir,
 
1558
                errors.ExistingLimbo)
1572
1559
            deletiondir = urlutils.local_path_from_url(
1573
1560
                tree._transport.abspath('pending-deletion'))
1574
 
            try:
1575
 
                os.mkdir(deletiondir)
1576
 
            except OSError, e:
1577
 
                if e.errno == errno.EEXIST:
1578
 
                    raise errors.ExistingPendingDeletion(deletiondir)
 
1561
            osutils.ensure_empty_directory_exists(
 
1562
                deletiondir,
 
1563
                errors.ExistingPendingDeletion)
1579
1564
        except:
1580
1565
            tree.unlock()
1581
1566
            raise
1644
1629
            else:
1645
1630
                raise
1646
1631
        if typefunc(mode):
1647
 
            os.chmod(self._limbo_name(trans_id), mode)
 
1632
            osutils.chmod_if_possible(self._limbo_name(trans_id), mode)
1648
1633
 
1649
1634
    def iter_tree_children(self, parent_id):
1650
1635
        """Iterate through the entry's tree children, if any"""
1728
1713
            calculating one.
1729
1714
        :param _mover: Supply an alternate FileMover, for testing
1730
1715
        """
 
1716
        for hook in MutableTree.hooks['pre_transform']:
 
1717
            hook(self._tree, self)
1731
1718
        if not no_conflicts:
1732
1719
            self._check_malformed()
1733
1720
        child_pb = ui.ui_factory.nested_progress_bar()
1734
1721
        try:
1735
1722
            if precomputed_delta is None:
1736
 
                child_pb.update('Apply phase', 0, 2)
 
1723
                child_pb.update(gettext('Apply phase'), 0, 2)
1737
1724
                inventory_delta = self._generate_inventory_delta()
1738
1725
                offset = 1
1739
1726
            else:
1744
1731
            else:
1745
1732
                mover = _mover
1746
1733
            try:
1747
 
                child_pb.update('Apply phase', 0 + offset, 2 + offset)
 
1734
                child_pb.update(gettext('Apply phase'), 0 + offset, 2 + offset)
1748
1735
                self._apply_removals(mover)
1749
 
                child_pb.update('Apply phase', 1 + offset, 2 + offset)
 
1736
                child_pb.update(gettext('Apply phase'), 1 + offset, 2 + offset)
1750
1737
                modified_paths = self._apply_insertions(mover)
1751
1738
            except:
1752
1739
                mover.rollback()
1755
1742
                mover.apply_deletions()
1756
1743
        finally:
1757
1744
            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] != '']
1758
1747
        self._tree.apply_inventory_delta(inventory_delta)
1759
1748
        self._apply_observed_sha1s()
1760
1749
        self._done = True
1770
1759
        try:
1771
1760
            for num, trans_id in enumerate(self._removed_id):
1772
1761
                if (num % 10) == 0:
1773
 
                    child_pb.update('removing file', num, total_entries)
 
1762
                    child_pb.update(gettext('removing file'), num, total_entries)
1774
1763
                if trans_id == self._new_root:
1775
1764
                    file_id = self._tree.get_root_id()
1776
1765
                else:
1788
1777
            final_kinds = {}
1789
1778
            for num, (path, trans_id) in enumerate(new_paths):
1790
1779
                if (num % 10) == 0:
1791
 
                    child_pb.update('adding file',
 
1780
                    child_pb.update(gettext('adding file'),
1792
1781
                                    num + len(self._removed_id), total_entries)
1793
1782
                file_id = new_path_file_ids[trans_id]
1794
1783
                if file_id is None:
1838
1827
                # do not attempt to move root into a subdirectory of itself.
1839
1828
                if path == '':
1840
1829
                    continue
1841
 
                child_pb.update('removing file', num, len(tree_paths))
 
1830
                child_pb.update(gettext('removing file'), num, len(tree_paths))
1842
1831
                full_path = self._tree.abspath(path)
1843
1832
                if trans_id in self._removed_contents:
1844
1833
                    delete_path = os.path.join(self._deletiondir, trans_id)
1873
1862
        try:
1874
1863
            for num, (path, trans_id) in enumerate(new_paths):
1875
1864
                if (num % 10) == 0:
1876
 
                    child_pb.update('adding file', num, len(new_paths))
 
1865
                    child_pb.update(gettext('adding file'), num, len(new_paths))
1877
1866
                full_path = self._tree.abspath(path)
1878
1867
                if trans_id in self._needs_rename:
1879
1868
                    try:
2062
2051
        pass
2063
2052
 
2064
2053
    @property
 
2054
    @deprecated_method(deprecated_in((2, 5, 0)))
2065
2055
    def inventory(self):
2066
2056
        """This Tree does not use inventory as its backing data."""
2067
2057
        raise NotImplementedError(_PreviewTree.inventory)
2068
2058
 
 
2059
    @property
 
2060
    def root_inventory(self):
 
2061
        """This Tree does not use inventory as its backing data."""
 
2062
        raise NotImplementedError(_PreviewTree.root_inventory)
 
2063
 
2069
2064
    def get_root_id(self):
2070
2065
        return self._transform.final_file_id(self._transform.root)
2071
2066
 
2117
2112
        return cur_parent
2118
2113
 
2119
2114
    def path2id(self, path):
 
2115
        if isinstance(path, list):
 
2116
            if path == []:
 
2117
                path = [""]
 
2118
            path = osutils.pathjoin(*path)
2120
2119
        return self._transform.final_file_id(self._path2trans_id(path))
2121
2120
 
2122
2121
    def id2path(self, file_id):
2263
2262
        else:
2264
2263
            return None
2265
2264
 
 
2265
    def get_file_verifier(self, file_id, path=None, stat_value=None):
 
2266
        trans_id = self._transform.trans_id_file_id(file_id)
 
2267
        kind = self._transform._new_contents.get(trans_id)
 
2268
        if kind is None:
 
2269
            return self._transform._tree.get_file_verifier(file_id)
 
2270
        if kind == 'file':
 
2271
            fileobj = self.get_file(file_id)
 
2272
            try:
 
2273
                return ("SHA1", sha_file(fileobj))
 
2274
            finally:
 
2275
                fileobj.close()
 
2276
 
2266
2277
    def get_file_sha1(self, file_id, path=None, stat_value=None):
2267
2278
        trans_id = self._transform.trans_id_file_id(file_id)
2268
2279
        kind = self._transform._new_contents.get(trans_id)
2318
2329
            if kind == 'file':
2319
2330
                statval = os.lstat(limbo_name)
2320
2331
                size = statval.st_size
2321
 
                if not supports_executable():
 
2332
                if not tt._limbo_supports_executable():
2322
2333
                    executable = False
2323
2334
                else:
2324
2335
                    executable = statval.st_mode & S_IEXEC
2539
2550
    file_trans_id = {}
2540
2551
    top_pb = ui.ui_factory.nested_progress_bar()
2541
2552
    pp = ProgressPhase("Build phase", 2, top_pb)
2542
 
    if tree.inventory.root is not None:
 
2553
    if tree.get_root_id() is not None:
2543
2554
        # This is kind of a hack: we should be altering the root
2544
2555
        # as part of the regular tree shape diff logic.
2545
2556
        # The conditional test here is to avoid doing an
2560
2571
        try:
2561
2572
            deferred_contents = []
2562
2573
            num = 0
2563
 
            total = len(tree.inventory)
 
2574
            total = len(tree.all_file_ids())
2564
2575
            if delta_from_tree:
2565
2576
                precomputed_delta = []
2566
2577
            else:
2575
2586
                for dir, files in wt.walkdirs():
2576
2587
                    existing_files.update(f[0] for f in files)
2577
2588
            for num, (tree_path, entry) in \
2578
 
                enumerate(tree.inventory.iter_entries_by_dir()):
2579
 
                pb.update("Building tree", num - len(deferred_contents), total)
 
2589
                enumerate(tree.iter_entries_by_dir()):
 
2590
                pb.update(gettext("Building tree"), num - len(deferred_contents), total)
2580
2591
                if entry.parent_id is None:
2581
2592
                    continue
2582
2593
                reparent = False
2588
2599
                    kind = file_kind(target_path)
2589
2600
                    if kind == "directory":
2590
2601
                        try:
2591
 
                            bzrdir.BzrDir.open(target_path)
 
2602
                            controldir.ControlDir.open(target_path)
2592
2603
                        except errors.NotBranchError:
2593
2604
                            pass
2594
2605
                        else:
2666
2677
                new_desired_files.append((file_id,
2667
2678
                    (trans_id, tree_path, text_sha1)))
2668
2679
                continue
2669
 
            pb.update('Adding file contents', count + offset, total)
 
2680
            pb.update(gettext('Adding file contents'), count + offset, total)
2670
2681
            if hardlink:
2671
2682
                tt.create_hardlink(accelerator_tree.abspath(accelerator_path),
2672
2683
                                   trans_id)
2693
2704
            contents = filtered_output_bytes(contents, filters,
2694
2705
                ContentFilterContext(tree_path, tree))
2695
2706
        tt.create_file(contents, trans_id, sha1=text_sha1)
2696
 
        pb.update('Adding file contents', count + offset, total)
 
2707
        pb.update(gettext('Adding file contents'), count + offset, total)
2697
2708
 
2698
2709
 
2699
2710
def _reparent_children(tt, old_parent, new_parent):
2813
2824
        tt.set_executability(entry.executable, trans_id)
2814
2825
 
2815
2826
 
2816
 
@deprecated_function(deprecated_in((2, 3, 0)))
2817
 
def get_backup_name(entry, by_parent, parent_trans_id, tt):
2818
 
    return _get_backup_name(entry.name, by_parent, parent_trans_id, tt)
2819
 
 
2820
 
 
2821
 
@deprecated_function(deprecated_in((2, 3, 0)))
2822
 
def _get_backup_name(name, by_parent, parent_trans_id, tt):
2823
 
    """Produce a backup-style name that appears to be available"""
2824
 
    def name_gen():
2825
 
        counter = 1
2826
 
        while True:
2827
 
            yield "%s.~%d~" % (name, counter)
2828
 
            counter += 1
2829
 
    for new_name in name_gen():
2830
 
        if not tt.has_named_child(by_parent, parent_trans_id, new_name):
2831
 
            return new_name
2832
 
 
2833
 
 
2834
 
def _entry_changes(file_id, entry, working_tree):
2835
 
    """Determine in which ways the inventory entry has changed.
2836
 
 
2837
 
    Returns booleans: has_contents, content_mod, meta_mod
2838
 
    has_contents means there are currently contents, but they differ
2839
 
    contents_mod means contents need to be modified
2840
 
    meta_mod means the metadata needs to be modified
2841
 
    """
2842
 
    cur_entry = working_tree.inventory[file_id]
2843
 
    try:
2844
 
        working_kind = working_tree.kind(file_id)
2845
 
        has_contents = True
2846
 
    except NoSuchFile:
2847
 
        has_contents = False
2848
 
        contents_mod = True
2849
 
        meta_mod = False
2850
 
    if has_contents is True:
2851
 
        if entry.kind != working_kind:
2852
 
            contents_mod, meta_mod = True, False
2853
 
        else:
2854
 
            cur_entry._read_tree_state(working_tree.id2path(file_id),
2855
 
                                       working_tree)
2856
 
            contents_mod, meta_mod = entry.detect_changes(cur_entry)
2857
 
            cur_entry._forget_tree_state()
2858
 
    return has_contents, contents_mod, meta_mod
2859
 
 
2860
 
 
2861
2827
def revert(working_tree, target_tree, filenames, backups=False,
2862
2828
           pb=None, change_reporter=None):
2863
2829
    """Revert a working tree's contents to those of a target tree."""
3040
3006
    pb = ui.ui_factory.nested_progress_bar()
3041
3007
    try:
3042
3008
        for n in range(10):
3043
 
            pb.update('Resolution pass', n+1, 10)
 
3009
            pb.update(gettext('Resolution pass'), n+1, 10)
3044
3010
            conflicts = tt.find_conflicts()
3045
3011
            if len(conflicts) == 0:
3046
3012
                return new_conflicts
3070
3036
                existing_file, new_file = conflict[2], conflict[1]
3071
3037
            else:
3072
3038
                existing_file, new_file = conflict[1], conflict[2]
3073
 
            new_name = tt.final_name(existing_file)+'.moved'
 
3039
            new_name = tt.final_name(existing_file) + '.moved'
3074
3040
            tt.adjust_path(new_name, final_parent, existing_file)
3075
3041
            new_conflicts.add((c_type, 'Moved existing file to',
3076
3042
                               existing_file, new_file))