~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transform.py

(gz) Fix deprecations of win32utils path function unicode wrappers (Martin
 Packman)

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
30
32
from bzrlib import (
31
33
    annotate,
32
34
    bencode,
33
 
    bzrdir,
 
35
    controldir,
34
36
    commit,
35
37
    conflicts,
36
38
    delta,
37
 
    errors,
38
39
    inventory,
39
40
    multiparent,
40
41
    osutils,
42
43
    ui,
43
44
    urlutils,
44
45
    )
 
46
from bzrlib.i18n import gettext
45
47
""")
46
 
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,
 
48
from bzrlib.errors import (DuplicateKey, MalformedTransform,
47
49
                           ReusingTransform, CantMoveRoot,
48
50
                           ExistingLimbo, ImmortalLimbo, NoFinalPath,
49
51
                           UnableCreateSymlink)
231
233
        new_roots = [k for k, v in self._new_parent.iteritems() if v is
232
234
                     ROOT_PARENT]
233
235
        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
236
            return
240
237
        if len(new_roots) != 1:
241
238
            raise ValueError('A tree cannot have two roots!')
243
240
            self._new_root = new_roots[0]
244
241
            return
245
242
        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
243
        # unversion the new root's directory.
252
 
        file_id = self.final_file_id(old_new_root)
 
244
        if self.final_kind(self._new_root) is None:
 
245
            file_id = self.final_file_id(old_new_root)
 
246
        else:
 
247
            file_id = self.final_file_id(self._new_root)
253
248
        if old_new_root in self._new_id:
254
249
            self.cancel_versioning(old_new_root)
255
250
        else:
568
563
        for trans_id in self._removed_id:
569
564
            file_id = self.tree_file_id(trans_id)
570
565
            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':
 
566
                if self._tree.stored_kind(file_id) == 'directory':
574
567
                    parents.append(trans_id)
575
568
            elif self.tree_kind(trans_id) == 'directory':
576
569
                parents.append(trans_id)
770
763
 
771
764
    def _set_executability(self, path, trans_id):
772
765
        """Set the executability of versioned files """
773
 
        if supports_executable():
 
766
        if self._tree._supports_executable():
774
767
            new_executability = self._new_executability[trans_id]
775
768
            abspath = self._tree.abspath(path)
776
769
            current_mode = os.stat(abspath).st_mode
785
778
                    to_mode |= 0010 & ~umask
786
779
            else:
787
780
                to_mode = current_mode & ~0111
788
 
            os.chmod(abspath, to_mode)
 
781
            osutils.chmod_if_possible(abspath, to_mode)
789
782
 
790
783
    def _new_entry(self, name, parent_id, file_id):
791
784
        """Helper function to create a new filesystem entry."""
1240
1233
        finally:
1241
1234
            TreeTransformBase.finalize(self)
1242
1235
 
 
1236
    def _limbo_supports_executable(self):
 
1237
        """Check if the limbo path supports the executable bit."""
 
1238
        # FIXME: Check actual file system capabilities of limbodir
 
1239
        return osutils.supports_executable()
 
1240
 
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)
1564
1562
        try:
1565
1563
            limbodir = urlutils.local_path_from_url(
1566
1564
                tree._transport.abspath('limbo'))
1567
 
            try:
1568
 
                os.mkdir(limbodir)
1569
 
            except OSError, e:
1570
 
                if e.errno == errno.EEXIST:
1571
 
                    raise ExistingLimbo(limbodir)
 
1565
            osutils.ensure_empty_directory_exists(
 
1566
                limbodir,
 
1567
                errors.ExistingLimbo)
1572
1568
            deletiondir = urlutils.local_path_from_url(
1573
1569
                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)
 
1570
            osutils.ensure_empty_directory_exists(
 
1571
                deletiondir,
 
1572
                errors.ExistingPendingDeletion)
1579
1573
        except:
1580
1574
            tree.unlock()
1581
1575
            raise
1644
1638
            else:
1645
1639
                raise
1646
1640
        if typefunc(mode):
1647
 
            os.chmod(self._limbo_name(trans_id), mode)
 
1641
            osutils.chmod_if_possible(self._limbo_name(trans_id), mode)
1648
1642
 
1649
1643
    def iter_tree_children(self, parent_id):
1650
1644
        """Iterate through the entry's tree children, if any"""
1733
1727
        child_pb = ui.ui_factory.nested_progress_bar()
1734
1728
        try:
1735
1729
            if precomputed_delta is None:
1736
 
                child_pb.update('Apply phase', 0, 2)
 
1730
                child_pb.update(gettext('Apply phase'), 0, 2)
1737
1731
                inventory_delta = self._generate_inventory_delta()
1738
1732
                offset = 1
1739
1733
            else:
1744
1738
            else:
1745
1739
                mover = _mover
1746
1740
            try:
1747
 
                child_pb.update('Apply phase', 0 + offset, 2 + offset)
 
1741
                child_pb.update(gettext('Apply phase'), 0 + offset, 2 + offset)
1748
1742
                self._apply_removals(mover)
1749
 
                child_pb.update('Apply phase', 1 + offset, 2 + offset)
 
1743
                child_pb.update(gettext('Apply phase'), 1 + offset, 2 + offset)
1750
1744
                modified_paths = self._apply_insertions(mover)
1751
1745
            except:
1752
1746
                mover.rollback()
1755
1749
                mover.apply_deletions()
1756
1750
        finally:
1757
1751
            child_pb.finished()
 
1752
        if self.final_file_id(self.root) is None:
 
1753
            inventory_delta = [e for e in inventory_delta if e[0] != '']
1758
1754
        self._tree.apply_inventory_delta(inventory_delta)
1759
1755
        self._apply_observed_sha1s()
1760
1756
        self._done = True
1770
1766
        try:
1771
1767
            for num, trans_id in enumerate(self._removed_id):
1772
1768
                if (num % 10) == 0:
1773
 
                    child_pb.update('removing file', num, total_entries)
 
1769
                    child_pb.update(gettext('removing file'), num, total_entries)
1774
1770
                if trans_id == self._new_root:
1775
1771
                    file_id = self._tree.get_root_id()
1776
1772
                else:
1788
1784
            final_kinds = {}
1789
1785
            for num, (path, trans_id) in enumerate(new_paths):
1790
1786
                if (num % 10) == 0:
1791
 
                    child_pb.update('adding file',
 
1787
                    child_pb.update(gettext('adding file'),
1792
1788
                                    num + len(self._removed_id), total_entries)
1793
1789
                file_id = new_path_file_ids[trans_id]
1794
1790
                if file_id is None:
1838
1834
                # do not attempt to move root into a subdirectory of itself.
1839
1835
                if path == '':
1840
1836
                    continue
1841
 
                child_pb.update('removing file', num, len(tree_paths))
 
1837
                child_pb.update(gettext('removing file'), num, len(tree_paths))
1842
1838
                full_path = self._tree.abspath(path)
1843
1839
                if trans_id in self._removed_contents:
1844
1840
                    delete_path = os.path.join(self._deletiondir, trans_id)
1873
1869
        try:
1874
1870
            for num, (path, trans_id) in enumerate(new_paths):
1875
1871
                if (num % 10) == 0:
1876
 
                    child_pb.update('adding file', num, len(new_paths))
 
1872
                    child_pb.update(gettext('adding file'), num, len(new_paths))
1877
1873
                full_path = self._tree.abspath(path)
1878
1874
                if trans_id in self._needs_rename:
1879
1875
                    try:
2263
2259
        else:
2264
2260
            return None
2265
2261
 
 
2262
    def get_file_verifier(self, file_id, path=None, stat_value=None):
 
2263
        trans_id = self._transform.trans_id_file_id(file_id)
 
2264
        kind = self._transform._new_contents.get(trans_id)
 
2265
        if kind is None:
 
2266
            return self._transform._tree.get_file_verifier(file_id)
 
2267
        if kind == 'file':
 
2268
            fileobj = self.get_file(file_id)
 
2269
            try:
 
2270
                return ("SHA1", sha_file(fileobj))
 
2271
            finally:
 
2272
                fileobj.close()
 
2273
 
2266
2274
    def get_file_sha1(self, file_id, path=None, stat_value=None):
2267
2275
        trans_id = self._transform.trans_id_file_id(file_id)
2268
2276
        kind = self._transform._new_contents.get(trans_id)
2318
2326
            if kind == 'file':
2319
2327
                statval = os.lstat(limbo_name)
2320
2328
                size = statval.st_size
2321
 
                if not supports_executable():
 
2329
                if not tt._limbo_supports_executable():
2322
2330
                    executable = False
2323
2331
                else:
2324
2332
                    executable = statval.st_mode & S_IEXEC
2539
2547
    file_trans_id = {}
2540
2548
    top_pb = ui.ui_factory.nested_progress_bar()
2541
2549
    pp = ProgressPhase("Build phase", 2, top_pb)
2542
 
    if tree.inventory.root is not None:
 
2550
    if tree.get_root_id() is not None:
2543
2551
        # This is kind of a hack: we should be altering the root
2544
2552
        # as part of the regular tree shape diff logic.
2545
2553
        # The conditional test here is to avoid doing an
2560
2568
        try:
2561
2569
            deferred_contents = []
2562
2570
            num = 0
2563
 
            total = len(tree.inventory)
 
2571
            total = len(tree.all_file_ids())
2564
2572
            if delta_from_tree:
2565
2573
                precomputed_delta = []
2566
2574
            else:
2575
2583
                for dir, files in wt.walkdirs():
2576
2584
                    existing_files.update(f[0] for f in files)
2577
2585
            for num, (tree_path, entry) in \
2578
 
                enumerate(tree.inventory.iter_entries_by_dir()):
2579
 
                pb.update("Building tree", num - len(deferred_contents), total)
 
2586
                enumerate(tree.iter_entries_by_dir()):
 
2587
                pb.update(gettext("Building tree"), num - len(deferred_contents), total)
2580
2588
                if entry.parent_id is None:
2581
2589
                    continue
2582
2590
                reparent = False
2588
2596
                    kind = file_kind(target_path)
2589
2597
                    if kind == "directory":
2590
2598
                        try:
2591
 
                            bzrdir.BzrDir.open(target_path)
 
2599
                            controldir.ControlDir.open(target_path)
2592
2600
                        except errors.NotBranchError:
2593
2601
                            pass
2594
2602
                        else:
2666
2674
                new_desired_files.append((file_id,
2667
2675
                    (trans_id, tree_path, text_sha1)))
2668
2676
                continue
2669
 
            pb.update('Adding file contents', count + offset, total)
 
2677
            pb.update(gettext('Adding file contents'), count + offset, total)
2670
2678
            if hardlink:
2671
2679
                tt.create_hardlink(accelerator_tree.abspath(accelerator_path),
2672
2680
                                   trans_id)
2693
2701
            contents = filtered_output_bytes(contents, filters,
2694
2702
                ContentFilterContext(tree_path, tree))
2695
2703
        tt.create_file(contents, trans_id, sha1=text_sha1)
2696
 
        pb.update('Adding file contents', count + offset, total)
 
2704
        pb.update(gettext('Adding file contents'), count + offset, total)
2697
2705
 
2698
2706
 
2699
2707
def _reparent_children(tt, old_parent, new_parent):
2831
2839
            return new_name
2832
2840
 
2833
2841
 
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
2842
def revert(working_tree, target_tree, filenames, backups=False,
2862
2843
           pb=None, change_reporter=None):
2863
2844
    """Revert a working tree's contents to those of a target tree."""
3040
3021
    pb = ui.ui_factory.nested_progress_bar()
3041
3022
    try:
3042
3023
        for n in range(10):
3043
 
            pb.update('Resolution pass', n+1, 10)
 
3024
            pb.update(gettext('Resolution pass'), n+1, 10)
3044
3025
            conflicts = tt.find_conflicts()
3045
3026
            if len(conflicts) == 0:
3046
3027
                return new_conflicts
3070
3051
                existing_file, new_file = conflict[2], conflict[1]
3071
3052
            else:
3072
3053
                existing_file, new_file = conflict[1], conflict[2]
3073
 
            new_name = tt.final_name(existing_file)+'.moved'
 
3054
            new_name = tt.final_name(existing_file) + '.moved'
3074
3055
            tt.adjust_path(new_name, final_parent, existing_file)
3075
3056
            new_conflicts.add((c_type, 'Moved existing file to',
3076
3057
                               existing_file, new_file))