~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

  • Committer: Martin von Gagern
  • Date: 2011-06-01 12:53:56 UTC
  • mto: This revision was merged to the branch mainline in revision 6009.
  • Revision ID: martin.vgagern@gmx.net-20110601125356-lwozv2vecea6hxfz
Change from no_decorate to classify as name for the argument.

The command line switch remains as --no-classify, to keep backwards
compatibility.  Users are free to include --no-classify in an alias, and
still use --classify to change back.

Show diffs side-by-side

added added

removed removed

Lines of Context:
54
54
    generate_ids,
55
55
    globbing,
56
56
    graph as _mod_graph,
 
57
    hashcache,
57
58
    ignores,
58
59
    inventory,
59
60
    merge,
71
72
 
72
73
from bzrlib import symbol_versioning
73
74
from bzrlib.decorators import needs_read_lock, needs_write_lock
74
 
from bzrlib.i18n import gettext
75
75
from bzrlib.lock import LogicalLockResult
76
76
import bzrlib.mutabletree
77
77
from bzrlib.mutabletree import needs_tree_write_lock
194
194
        self.basedir = realpath(basedir)
195
195
        self._control_files = _control_files
196
196
        self._transport = self._control_files._transport
 
197
        # update the whole cache up front and write to disk if anything changed;
 
198
        # in the future we might want to do this more selectively
 
199
        # two possible ways offer themselves : in self._unlock, write the cache
 
200
        # if needed, or, when the cache sees a change, append it to the hash
 
201
        # cache file, and have the parser take the most recent entry for a
 
202
        # given path only.
 
203
        wt_trans = self.bzrdir.get_workingtree_transport(None)
 
204
        cache_filename = wt_trans.local_abspath('stat-cache')
 
205
        self._hashcache = hashcache.HashCache(basedir, cache_filename,
 
206
            self.bzrdir._get_file_mode(),
 
207
            self._content_filter_stack_provider())
 
208
        hc = self._hashcache
 
209
        hc.read()
 
210
        # is this scan needed ? it makes things kinda slow.
 
211
        #hc.scan()
 
212
 
 
213
        if hc.needs_write:
 
214
            mutter("write hc")
 
215
            hc.write()
 
216
 
 
217
        self._detect_case_handling()
197
218
        self._rules_searcher = None
198
219
        self.views = self._make_views()
199
220
 
217
238
        """
218
239
        return self.bzrdir.is_control_filename(filename)
219
240
 
 
241
    def _detect_case_handling(self):
 
242
        wt_trans = self.bzrdir.get_workingtree_transport(None)
 
243
        try:
 
244
            wt_trans.stat(self._format.case_sensitive_filename)
 
245
        except errors.NoSuchFile:
 
246
            self.case_sensitive = True
 
247
        else:
 
248
            self.case_sensitive = False
 
249
 
 
250
        self._setup_directory_is_tree_reference()
 
251
 
220
252
    branch = property(
221
253
        fget=lambda self: self._branch,
222
254
        doc="""The branch this WorkingTree is connected to.
225
257
            the working tree has been constructed from.
226
258
            """)
227
259
 
228
 
    def has_versioned_directories(self):
229
 
        """See `Tree.has_versioned_directories`."""
230
 
        return self._format.supports_versioned_directories
231
 
 
232
260
    def break_lock(self):
233
261
        """Break a lock if one is present from another instance.
234
262
 
303
331
                if view_files:
304
332
                    file_list = view_files
305
333
                    view_str = views.view_display_str(view_files)
306
 
                    note(gettext("Ignoring files outside view. View is %s") % view_str)
 
334
                    note("Ignoring files outside view. View is %s" % view_str)
307
335
            return tree, file_list
308
336
        if default_directory == u'.':
309
337
            seed = file_list[0]
468
496
        finally:
469
497
            file.close()
470
498
 
 
499
    def _get_ancestors(self, default_revision):
 
500
        ancestors = set([default_revision])
 
501
        for parent_id in self.get_parent_ids():
 
502
            ancestors.update(self.branch.repository.get_ancestry(
 
503
                             parent_id, topo_sorted=False))
 
504
        return ancestors
 
505
 
471
506
    def get_parent_ids(self):
472
507
        """See Tree.get_parent_ids.
473
508
 
567
602
            else:
568
603
                return None
569
604
 
 
605
    def get_file_sha1(self, file_id, path=None, stat_value=None):
 
606
        # FIXME: Shouldn't this be in Tree?
 
607
        raise NotImplementedError(self.get_file_sha1)
 
608
 
570
609
    @needs_tree_write_lock
571
610
    def _gather_kinds(self, files, kinds):
572
611
        """See MutableTree._gather_kinds."""
934
973
        file and change the file_id. That is the normal mode. Second, it can
935
974
        only change the file_id without touching any physical file.
936
975
 
937
 
        rename_one uses the second mode if 'after == True' and 'to_rel' is
938
 
        either not versioned or newly added, and present in the working tree.
 
976
        rename_one uses the second mode if 'after == True' and 'to_rel' is not
 
977
        versioned but present in the working tree.
939
978
 
940
979
        rename_one uses the second mode if 'after == False' and 'from_rel' is
941
980
        versioned but no longer in the working tree, and 'to_rel' is not
1034
1073
            stream.write(bytes)
1035
1074
        finally:
1036
1075
            stream.close()
 
1076
        # TODO: update the hashcache here ?
1037
1077
 
1038
1078
    def extras(self):
1039
1079
        """Yield all unversioned files in this WorkingTree.
1345
1385
    def revert(self, filenames=None, old_tree=None, backups=True,
1346
1386
               pb=None, report_changes=False):
1347
1387
        from bzrlib.conflicts import resolve
 
1388
        if filenames == []:
 
1389
            filenames = None
 
1390
            symbol_versioning.warn('Using [] to revert all files is deprecated'
 
1391
                ' as of bzr 0.91.  Please use None (the default) instead.',
 
1392
                DeprecationWarning, stacklevel=2)
1348
1393
        if old_tree is None:
1349
1394
            basis_tree = self.basis_tree()
1350
1395
            basis_tree.lock_read()
1499
1544
                                             show_base=show_base)
1500
1545
            if nb_conflicts:
1501
1546
                self.add_parent_tree((old_tip, other_tree))
1502
 
                note(gettext('Rerun update after fixing the conflicts.'))
 
1547
                note('Rerun update after fixing the conflicts.')
1503
1548
                return nb_conflicts
1504
1549
 
1505
1550
        if last_rev != _mod_revision.ensure_null(revision):
1547
1592
            last_rev = parent_trees[0][0]
1548
1593
        return nb_conflicts
1549
1594
 
 
1595
    def _write_hashcache_if_dirty(self):
 
1596
        """Write out the hashcache if it is dirty."""
 
1597
        if self._hashcache.needs_write:
 
1598
            try:
 
1599
                self._hashcache.write()
 
1600
            except OSError, e:
 
1601
                if e.errno not in (errno.EPERM, errno.EACCES):
 
1602
                    raise
 
1603
                # TODO: jam 20061219 Should this be a warning? A single line
 
1604
                #       warning might be sufficient to let the user know what
 
1605
                #       is going on.
 
1606
                mutter('Could not write hashcache for %s\nError: %s',
 
1607
                              self._hashcache.cache_file_name(), e)
 
1608
 
1550
1609
    def set_conflicts(self, arg):
1551
1610
        raise errors.UnsupportedOperation(self.set_conflicts, self)
1552
1611
 
1784
1843
            branch=branch, _control_files=_control_files, _internal=_internal,
1785
1844
            _format=_format, _bzrdir=_bzrdir)
1786
1845
 
1787
 
        self._detect_case_handling()
1788
 
 
1789
1846
        if _inventory is None:
1790
1847
            # This will be acquired on lock_read() or lock_write()
1791
1848
            self._inventory_is_modified = False
1810
1867
        self._inventory = inv
1811
1868
        self._inventory_is_modified = dirty
1812
1869
 
1813
 
    def _detect_case_handling(self):
1814
 
        wt_trans = self.bzrdir.get_workingtree_transport(None)
1815
 
        try:
1816
 
            wt_trans.stat(self._format.case_sensitive_filename)
1817
 
        except errors.NoSuchFile:
1818
 
            self.case_sensitive = True
1819
 
        else:
1820
 
            self.case_sensitive = False
1821
 
 
1822
 
        self._setup_directory_is_tree_reference()
1823
 
 
1824
1870
    def _serialize(self, inventory, out_file):
1825
1871
        xml5.serializer_v5.write_inventory(self._inventory, out_file,
1826
1872
            working=True)
2043
2089
            return True
2044
2090
        return self.inventory.has_id(file_id)
2045
2091
 
 
2092
    __contains__ = has_id
 
2093
 
2046
2094
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
2047
2095
    def __iter__(self):
2048
2096
        """Iterate through file_ids for this tree.
2130
2178
            mode=self.bzrdir._get_file_mode())
2131
2179
        self._inventory_is_modified = False
2132
2180
 
 
2181
    @needs_read_lock
 
2182
    def get_file_sha1(self, file_id, path=None, stat_value=None):
 
2183
        if not path:
 
2184
            path = self._inventory.id2path(file_id)
 
2185
        return self._hashcache.get_sha1(path, stat_value)
 
2186
 
2133
2187
    def get_file_mtime(self, file_id, path=None):
2134
2188
        """See Tree.get_file_mtime."""
2135
2189
        if not path:
2136
2190
            path = self.inventory.id2path(file_id)
2137
 
        try:
2138
 
            return os.lstat(self.abspath(path)).st_mtime
2139
 
        except OSError, e:
2140
 
            if e.errno == errno.ENOENT:
2141
 
                raise errors.FileTimestampUnavailable(path)
2142
 
            raise
 
2191
        return os.lstat(self.abspath(path)).st_mtime
2143
2192
 
2144
2193
    def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
2145
2194
        file_id = self.path2id(path)
2223
2272
                parent_tree = self.branch.repository.revision_tree(parent_id)
2224
2273
            parent_tree.lock_read()
2225
2274
            try:
2226
 
                if not parent_tree.has_id(file_id):
 
2275
                if file_id not in parent_tree:
2227
2276
                    continue
2228
2277
                ie = parent_tree.inventory[file_id]
2229
2278
                if ie.kind != 'file':
2277
2326
            for s in _mod_rio.RioReader(hashfile):
2278
2327
                # RioReader reads in Unicode, so convert file_ids back to utf8
2279
2328
                file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
2280
 
                if not self.inventory.has_id(file_id):
 
2329
                if file_id not in self.inventory:
2281
2330
                    continue
2282
2331
                text_hash = s.get("hash")
2283
2332
                if text_hash == self.get_file_sha1(file_id):
2524
2573
        inventory. The second mode only updates the inventory without
2525
2574
        touching the file on the filesystem.
2526
2575
 
2527
 
        move uses the second mode if 'after == True' and the target is
2528
 
        either not versioned or newly added, and present in the working tree.
 
2576
        move uses the second mode if 'after == True' and the target is not
 
2577
        versioned but present in the working tree.
2529
2578
 
2530
2579
        move uses the second mode if 'after == False' and the source is
2531
2580
        versioned but no longer in the working tree, and the target is not
2678
2727
 
2679
2728
    class _RenameEntry(object):
2680
2729
        def __init__(self, from_rel, from_id, from_tail, from_parent_id,
2681
 
                     to_rel, to_tail, to_parent_id, only_change_inv=False,
2682
 
                     change_id=False):
 
2730
                     to_rel, to_tail, to_parent_id, only_change_inv=False):
2683
2731
            self.from_rel = from_rel
2684
2732
            self.from_id = from_id
2685
2733
            self.from_tail = from_tail
2687
2735
            self.to_rel = to_rel
2688
2736
            self.to_tail = to_tail
2689
2737
            self.to_parent_id = to_parent_id
2690
 
            self.change_id = change_id
2691
2738
            self.only_change_inv = only_change_inv
2692
2739
 
2693
2740
    def _determine_mv_mode(self, rename_entries, after=False):
2705
2752
            to_rel = rename_entry.to_rel
2706
2753
            to_id = inv.path2id(to_rel)
2707
2754
            only_change_inv = False
2708
 
            change_id = False
2709
2755
 
2710
2756
            # check the inventory for source and destination
2711
2757
            if from_id is None:
2712
2758
                raise errors.BzrMoveFailedError(from_rel,to_rel,
2713
2759
                    errors.NotVersionedError(path=from_rel))
2714
2760
            if to_id is not None:
2715
 
                allowed = False
2716
 
                # allow it with --after but only if dest is newly added
2717
 
                if after:
2718
 
                    basis = self.basis_tree()
2719
 
                    basis.lock_read()
2720
 
                    try:
2721
 
                        if not basis.has_id(to_id):
2722
 
                            rename_entry.change_id = True
2723
 
                            allowed = True
2724
 
                    finally:
2725
 
                        basis.unlock()
2726
 
                if not allowed:
2727
 
                    raise errors.BzrMoveFailedError(from_rel,to_rel,
2728
 
                        errors.AlreadyVersionedError(path=to_rel))
 
2761
                raise errors.BzrMoveFailedError(from_rel,to_rel,
 
2762
                    errors.AlreadyVersionedError(path=to_rel))
2729
2763
 
2730
2764
            # try to determine the mode for rename (only change inv or change
2731
2765
            # inv and file system)
2802
2836
            except OSError, e:
2803
2837
                raise errors.BzrMoveFailedError(entry.from_rel,
2804
2838
                    entry.to_rel, e[1])
2805
 
        if entry.change_id:
2806
 
            to_id = inv.path2id(entry.to_rel)
2807
 
            inv.remove_recursive_id(to_id)
2808
2839
        inv.rename(entry.from_id, entry.to_parent_id, entry.to_tail)
2809
2840
 
2810
2841
    @needs_tree_write_lock
2818
2849
        :raises: NoSuchId if any fileid is not currently versioned.
2819
2850
        """
2820
2851
        for file_id in file_ids:
2821
 
            if not self._inventory.has_id(file_id):
 
2852
            if file_id not in self._inventory:
2822
2853
                raise errors.NoSuchId(self, file_id)
2823
2854
        for file_id in file_ids:
2824
2855
            if self._inventory.has_id(file_id):
2979
3010
    missing_parent_conflicts = False
2980
3011
    """If this format supports missing parent conflicts."""
2981
3012
 
2982
 
    supports_versioned_directories = None
2983
 
 
2984
3013
    @classmethod
2985
3014
    def find_format_string(klass, a_bzrdir):
2986
3015
        """Return format name for the working tree object in a_bzrdir."""
3091
3120
    def unregister_format(klass, format):
3092
3121
        format_registry.remove(format)
3093
3122
 
3094
 
    def get_controldir_for_branch(self):
3095
 
        """Get the control directory format for creating branches.
3096
 
 
3097
 
        This is to support testing of working tree formats that can not exist
3098
 
        in the same control directory as a branch.
3099
 
        """
3100
 
        return self._matchingbzrdir
3101
 
 
3102
3123
 
3103
3124
format_registry.register_lazy("Bazaar Working Tree Format 4 (bzr 0.15)\n",
3104
3125
    "bzrlib.workingtree_4", "WorkingTreeFormat4")