~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transform.py

  • Committer: Samuel Bronson
  • Date: 2012-08-30 20:36:18 UTC
  • mto: (6015.57.3 2.4)
  • mto: This revision was merged to the branch mainline in revision 6558.
  • Revision ID: naesten@gmail.com-20120830203618-y2dzw91nqpvpgxvx
Update INSTALL for switch to Python 2.6 and up.

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
 
 
19
17
import os
20
18
import errno
21
19
from stat import S_ISREG, S_IEXEC
32
30
from bzrlib import (
33
31
    annotate,
34
32
    bencode,
35
 
    controldir,
 
33
    bzrdir,
36
34
    commit,
37
35
    conflicts,
38
36
    delta,
 
37
    errors,
39
38
    inventory,
40
39
    multiparent,
41
40
    osutils,
43
42
    ui,
44
43
    urlutils,
45
44
    )
46
 
from bzrlib.i18n import gettext
47
45
""")
48
 
from bzrlib.errors import (DuplicateKey, MalformedTransform,
 
46
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,
49
47
                           ReusingTransform, CantMoveRoot,
50
 
                           ImmortalLimbo, NoFinalPath,
 
48
                           ExistingLimbo, ImmortalLimbo, NoFinalPath,
51
49
                           UnableCreateSymlink)
52
50
from bzrlib.filters import filtered_output_bytes, ContentFilterContext
53
 
from bzrlib.mutabletree import MutableTree
54
51
from bzrlib.osutils import (
55
52
    delete_any,
56
53
    file_kind,
58
55
    pathjoin,
59
56
    sha_file,
60
57
    splitpath,
 
58
    supports_executable,
61
59
    )
62
60
from bzrlib.progress import ProgressPhase
63
61
from bzrlib.symbol_versioning import (
156
154
        """
157
155
        if self._tree is None:
158
156
            return
159
 
        for hook in MutableTree.hooks['post_transform']:
160
 
            hook(self._tree, self)
161
157
        self._tree.unlock()
162
158
        self._tree = None
163
159
 
232
228
        irrelevant.
233
229
 
234
230
        """
235
 
        new_roots = [k for k, v in self._new_parent.iteritems() if v ==
 
231
        new_roots = [k for k, v in self._new_parent.iteritems() if v is
236
232
                     ROOT_PARENT]
237
233
        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)
238
239
            return
239
240
        if len(new_roots) != 1:
240
241
            raise ValueError('A tree cannot have two roots!')
565
566
        for trans_id in self._removed_id:
566
567
            file_id = self.tree_file_id(trans_id)
567
568
            if file_id is not None:
568
 
                if self._tree.stored_kind(file_id) == 'directory':
 
569
                # XXX: This seems like something that should go via a different
 
570
                #      indirection.
 
571
                if self._tree.inventory[file_id].kind == 'directory':
569
572
                    parents.append(trans_id)
570
573
            elif self.tree_kind(trans_id) == 'directory':
571
574
                parents.append(trans_id)
628
631
        for trans_id in self._new_parent:
629
632
            seen = set()
630
633
            parent_id = trans_id
631
 
            while parent_id != ROOT_PARENT:
 
634
            while parent_id is not ROOT_PARENT:
632
635
                seen.add(parent_id)
633
636
                try:
634
637
                    parent_id = self.final_parent(parent_id)
644
647
        """If parent directories are versioned, children must be versioned."""
645
648
        conflicts = []
646
649
        for parent_id, children in by_parent.iteritems():
647
 
            if parent_id == ROOT_PARENT:
 
650
            if parent_id is ROOT_PARENT:
648
651
                continue
649
652
            if self.final_file_id(parent_id) is not None:
650
653
                continue
743
746
        """Children must have a directory parent"""
744
747
        conflicts = []
745
748
        for parent_id, children in by_parent.iteritems():
746
 
            if parent_id == ROOT_PARENT:
 
749
            if parent_id is ROOT_PARENT:
747
750
                continue
748
751
            no_children = True
749
752
            for child_id in children:
765
768
 
766
769
    def _set_executability(self, path, trans_id):
767
770
        """Set the executability of versioned files """
768
 
        if self._tree._supports_executable():
 
771
        if supports_executable():
769
772
            new_executability = self._new_executability[trans_id]
770
773
            abspath = self._tree.abspath(path)
771
774
            current_mode = os.stat(abspath).st_mode
1235
1238
        finally:
1236
1239
            TreeTransformBase.finalize(self)
1237
1240
 
1238
 
    def _limbo_supports_executable(self):
1239
 
        """Check if the limbo path supports the executable bit."""
1240
 
        # FIXME: Check actual file system capabilities of limbodir
1241
 
        return osutils.supports_executable()
1242
 
 
1243
1241
    def _limbo_name(self, trans_id):
1244
1242
        """Generate the limbo name of a file"""
1245
1243
        limbo_name = self._limbo_files.get(trans_id)
1724
1722
            calculating one.
1725
1723
        :param _mover: Supply an alternate FileMover, for testing
1726
1724
        """
1727
 
        for hook in MutableTree.hooks['pre_transform']:
1728
 
            hook(self._tree, self)
1729
1725
        if not no_conflicts:
1730
1726
            self._check_malformed()
1731
1727
        child_pb = ui.ui_factory.nested_progress_bar()
1732
1728
        try:
1733
1729
            if precomputed_delta is None:
1734
 
                child_pb.update(gettext('Apply phase'), 0, 2)
 
1730
                child_pb.update('Apply phase', 0, 2)
1735
1731
                inventory_delta = self._generate_inventory_delta()
1736
1732
                offset = 1
1737
1733
            else:
1742
1738
            else:
1743
1739
                mover = _mover
1744
1740
            try:
1745
 
                child_pb.update(gettext('Apply phase'), 0 + offset, 2 + offset)
 
1741
                child_pb.update('Apply phase', 0 + offset, 2 + offset)
1746
1742
                self._apply_removals(mover)
1747
 
                child_pb.update(gettext('Apply phase'), 1 + offset, 2 + offset)
 
1743
                child_pb.update('Apply phase', 1 + offset, 2 + offset)
1748
1744
                modified_paths = self._apply_insertions(mover)
1749
1745
            except:
1750
1746
                mover.rollback()
1753
1749
                mover.apply_deletions()
1754
1750
        finally:
1755
1751
            child_pb.finished()
1756
 
        if self.final_file_id(self.root) is None:
1757
 
            inventory_delta = [e for e in inventory_delta if e[0] != '']
1758
1752
        self._tree.apply_inventory_delta(inventory_delta)
1759
1753
        self._apply_observed_sha1s()
1760
1754
        self._done = True
1770
1764
        try:
1771
1765
            for num, trans_id in enumerate(self._removed_id):
1772
1766
                if (num % 10) == 0:
1773
 
                    child_pb.update(gettext('removing file'), num, total_entries)
 
1767
                    child_pb.update('removing file', num, total_entries)
1774
1768
                if trans_id == self._new_root:
1775
1769
                    file_id = self._tree.get_root_id()
1776
1770
                else:
1788
1782
            final_kinds = {}
1789
1783
            for num, (path, trans_id) in enumerate(new_paths):
1790
1784
                if (num % 10) == 0:
1791
 
                    child_pb.update(gettext('adding file'),
 
1785
                    child_pb.update('adding file',
1792
1786
                                    num + len(self._removed_id), total_entries)
1793
1787
                file_id = new_path_file_ids[trans_id]
1794
1788
                if file_id is None:
1838
1832
                # do not attempt to move root into a subdirectory of itself.
1839
1833
                if path == '':
1840
1834
                    continue
1841
 
                child_pb.update(gettext('removing file'), num, len(tree_paths))
 
1835
                child_pb.update('removing file', num, len(tree_paths))
1842
1836
                full_path = self._tree.abspath(path)
1843
1837
                if trans_id in self._removed_contents:
1844
1838
                    delete_path = os.path.join(self._deletiondir, trans_id)
1873
1867
        try:
1874
1868
            for num, (path, trans_id) in enumerate(new_paths):
1875
1869
                if (num % 10) == 0:
1876
 
                    child_pb.update(gettext('adding file'), num, len(new_paths))
 
1870
                    child_pb.update('adding file', num, len(new_paths))
1877
1871
                full_path = self._tree.abspath(path)
1878
1872
                if trans_id in self._needs_rename:
1879
1873
                    try:
2263
2257
        else:
2264
2258
            return None
2265
2259
 
2266
 
    def get_file_verifier(self, file_id, path=None, stat_value=None):
2267
 
        trans_id = self._transform.trans_id_file_id(file_id)
2268
 
        kind = self._transform._new_contents.get(trans_id)
2269
 
        if kind is None:
2270
 
            return self._transform._tree.get_file_verifier(file_id)
2271
 
        if kind == 'file':
2272
 
            fileobj = self.get_file(file_id)
2273
 
            try:
2274
 
                return ("SHA1", sha_file(fileobj))
2275
 
            finally:
2276
 
                fileobj.close()
2277
 
 
2278
2260
    def get_file_sha1(self, file_id, path=None, stat_value=None):
2279
2261
        trans_id = self._transform.trans_id_file_id(file_id)
2280
2262
        kind = self._transform._new_contents.get(trans_id)
2330
2312
            if kind == 'file':
2331
2313
                statval = os.lstat(limbo_name)
2332
2314
                size = statval.st_size
2333
 
                if not tt._limbo_supports_executable():
 
2315
                if not supports_executable():
2334
2316
                    executable = False
2335
2317
                else:
2336
2318
                    executable = statval.st_mode & S_IEXEC
2551
2533
    file_trans_id = {}
2552
2534
    top_pb = ui.ui_factory.nested_progress_bar()
2553
2535
    pp = ProgressPhase("Build phase", 2, top_pb)
2554
 
    if tree.get_root_id() is not None:
 
2536
    if tree.inventory.root is not None:
2555
2537
        # This is kind of a hack: we should be altering the root
2556
2538
        # as part of the regular tree shape diff logic.
2557
2539
        # The conditional test here is to avoid doing an
2572
2554
        try:
2573
2555
            deferred_contents = []
2574
2556
            num = 0
2575
 
            total = len(tree.all_file_ids())
 
2557
            total = len(tree.inventory)
2576
2558
            if delta_from_tree:
2577
2559
                precomputed_delta = []
2578
2560
            else:
2587
2569
                for dir, files in wt.walkdirs():
2588
2570
                    existing_files.update(f[0] for f in files)
2589
2571
            for num, (tree_path, entry) in \
2590
 
                enumerate(tree.iter_entries_by_dir()):
2591
 
                pb.update(gettext("Building tree"), num - len(deferred_contents), total)
 
2572
                enumerate(tree.inventory.iter_entries_by_dir()):
 
2573
                pb.update("Building tree", num - len(deferred_contents), total)
2592
2574
                if entry.parent_id is None:
2593
2575
                    continue
2594
2576
                reparent = False
2600
2582
                    kind = file_kind(target_path)
2601
2583
                    if kind == "directory":
2602
2584
                        try:
2603
 
                            controldir.ControlDir.open(target_path)
 
2585
                            bzrdir.BzrDir.open(target_path)
2604
2586
                        except errors.NotBranchError:
2605
2587
                            pass
2606
2588
                        else:
2678
2660
                new_desired_files.append((file_id,
2679
2661
                    (trans_id, tree_path, text_sha1)))
2680
2662
                continue
2681
 
            pb.update(gettext('Adding file contents'), count + offset, total)
 
2663
            pb.update('Adding file contents', count + offset, total)
2682
2664
            if hardlink:
2683
2665
                tt.create_hardlink(accelerator_tree.abspath(accelerator_path),
2684
2666
                                   trans_id)
2705
2687
            contents = filtered_output_bytes(contents, filters,
2706
2688
                ContentFilterContext(tree_path, tree))
2707
2689
        tt.create_file(contents, trans_id, sha1=text_sha1)
2708
 
        pb.update(gettext('Adding file contents'), count + offset, total)
 
2690
        pb.update('Adding file contents', count + offset, total)
2709
2691
 
2710
2692
 
2711
2693
def _reparent_children(tt, old_parent, new_parent):
2843
2825
            return new_name
2844
2826
 
2845
2827
 
 
2828
def _entry_changes(file_id, entry, working_tree):
 
2829
    """Determine in which ways the inventory entry has changed.
 
2830
 
 
2831
    Returns booleans: has_contents, content_mod, meta_mod
 
2832
    has_contents means there are currently contents, but they differ
 
2833
    contents_mod means contents need to be modified
 
2834
    meta_mod means the metadata needs to be modified
 
2835
    """
 
2836
    cur_entry = working_tree.inventory[file_id]
 
2837
    try:
 
2838
        working_kind = working_tree.kind(file_id)
 
2839
        has_contents = True
 
2840
    except NoSuchFile:
 
2841
        has_contents = False
 
2842
        contents_mod = True
 
2843
        meta_mod = False
 
2844
    if has_contents is True:
 
2845
        if entry.kind != working_kind:
 
2846
            contents_mod, meta_mod = True, False
 
2847
        else:
 
2848
            cur_entry._read_tree_state(working_tree.id2path(file_id),
 
2849
                                       working_tree)
 
2850
            contents_mod, meta_mod = entry.detect_changes(cur_entry)
 
2851
            cur_entry._forget_tree_state()
 
2852
    return has_contents, contents_mod, meta_mod
 
2853
 
 
2854
 
2846
2855
def revert(working_tree, target_tree, filenames, backups=False,
2847
2856
           pb=None, change_reporter=None):
2848
2857
    """Revert a working tree's contents to those of a target tree."""
3025
3034
    pb = ui.ui_factory.nested_progress_bar()
3026
3035
    try:
3027
3036
        for n in range(10):
3028
 
            pb.update(gettext('Resolution pass'), n+1, 10)
 
3037
            pb.update('Resolution pass', n+1, 10)
3029
3038
            conflicts = tt.find_conflicts()
3030
3039
            if len(conflicts) == 0:
3031
3040
                return new_conflicts